From 3f7dfd711dfc6a3563babbad3596bea1224d52a2 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Sat, 18 Nov 2023 13:20:58 -0800 Subject: [PATCH 1/5] remove older protocol implementation --- .github/workflows/dart_pad.yml | 4 - .github/workflows/dart_services.yml | 3 - CONTRIBUTING.md | 5 +- pkgs/dart_pad/pubspec.lock | 46 +- pkgs/dart_pad/pubspec.yaml | 3 +- pkgs/dart_services/README.md | 16 - pkgs/dart_services/lib/server.dart | 55 +- pkgs/dart_services/lib/src/analysis.dart | 534 ++++ .../lib/src/analysis_server.dart | 731 ----- .../lib/src/analyzer_wrapper.dart | 212 -- .../src/{server_cache.dart => caching.dart} | 4 +- pkgs/dart_services/lib/src/common.dart | 875 +----- pkgs/dart_services/lib/src/common_server.dart | 326 ++ .../lib/src/common_server.g.dart | 52 + .../lib/src/common_server_api.dart | 624 ---- .../lib/src/common_server_api.g.dart | 192 -- .../lib/src/common_server_impl.dart | 403 --- .../lib/src/{compiler.dart => compiling.dart} | 178 +- ..._oauth_handler.dart => oauth_handler.dart} | 2 +- .../lib/src/project_creator.dart | 51 +- .../{project.dart => project_templates.dart} | 10 +- .../lib/src/protos/dart_services.pb.dart | 2764 ----------------- .../lib/src/protos/dart_services.pbenum.dart | 10 - .../lib/src/protos/dart_services.pbjson.dart | 802 ----- .../src/protos/dart_services.pbserver.dart | 13 - pkgs/dart_services/lib/src/pub.dart | 29 +- pkgs/dart_services/lib/src/scheduler.dart | 66 - pkgs/dart_services/lib/src/sdk.dart | 14 +- pkgs/dart_services/lib/src/shared/model.dart | 23 +- .../dart_services/lib/src/shared/model.g.dart | 14 +- .../lib/src/shared/services.dart | 5 - pkgs/dart_services/lib/src/shelf_cors.dart | 8 +- pkgs/dart_services/lib/src/utils.dart | 73 +- pkgs/dart_services/protos/dart_services.proto | 267 -- pkgs/dart_services/pubspec.lock | 48 +- pkgs/dart_services/pubspec.yaml | 3 - .../test/analysis_server_test.dart | 408 --- pkgs/dart_services/test/analysis_test.dart | 329 ++ ...edis_cache_test.dart => caching_test.dart} | 5 +- .../test/common_server_api_protobuf_test.dart | 740 ----- .../test/common_server_api_test.dart | 1086 ------- pkgs/dart_services/test/common_test.dart | 71 - pkgs/dart_services/test/compiler_test.dart | 434 --- pkgs/dart_services/test/compiling_test.dart | 216 ++ .../test/flutter_analysis_server_test.dart | 344 -- pkgs/dart_services/test/flutter_web_test.dart | 4 +- .../dart_services/test/gae_deployed_test.dart | 64 - .../test/project_creator_test.dart | 369 +-- pkgs/dart_services/test/pub_test.dart | 138 +- pkgs/dart_services/test/shelf_cors_test.dart | 2 +- pkgs/dart_services/test/src/sample_code.dart | 725 +++++ pkgs/dart_services/test/src/utils.dart | 5 +- pkgs/dart_services/test/utils_test.dart | 88 +- .../dependencies/pub_dependencies_main.json | 2 +- pkgs/dart_services/tool/grind.dart | 43 +- pkgs/dartpad_shared/lib/model.dart | 23 +- pkgs/dartpad_shared/lib/model.g.dart | 14 +- pkgs/dartpad_shared/lib/services.dart | 5 - pkgs/samples/pubspec.yaml | 2 - pkgs/sketch_pad/lib/model.dart | 13 +- pkgs/sketch_pad/pubspec.yaml | 1 - 61 files changed, 2770 insertions(+), 10826 deletions(-) create mode 100644 pkgs/dart_services/lib/src/analysis.dart delete mode 100644 pkgs/dart_services/lib/src/analysis_server.dart delete mode 100644 pkgs/dart_services/lib/src/analyzer_wrapper.dart rename pkgs/dart_services/lib/src/{server_cache.dart => caching.dart} (99%) create mode 100644 pkgs/dart_services/lib/src/common_server.dart create mode 100644 pkgs/dart_services/lib/src/common_server.g.dart delete mode 100644 pkgs/dart_services/lib/src/common_server_api.dart delete mode 100644 pkgs/dart_services/lib/src/common_server_api.g.dart delete mode 100644 pkgs/dart_services/lib/src/common_server_impl.dart rename pkgs/dart_services/lib/src/{compiler.dart => compiling.dart} (60%) rename pkgs/dart_services/lib/src/{github_oauth_handler.dart => oauth_handler.dart} (99%) rename pkgs/dart_services/lib/src/{project.dart => project_templates.dart} (97%) delete mode 100644 pkgs/dart_services/lib/src/protos/dart_services.pb.dart delete mode 100644 pkgs/dart_services/lib/src/protos/dart_services.pbenum.dart delete mode 100644 pkgs/dart_services/lib/src/protos/dart_services.pbjson.dart delete mode 100644 pkgs/dart_services/lib/src/protos/dart_services.pbserver.dart delete mode 100644 pkgs/dart_services/lib/src/scheduler.dart delete mode 100644 pkgs/dart_services/protos/dart_services.proto delete mode 100644 pkgs/dart_services/test/analysis_server_test.dart create mode 100644 pkgs/dart_services/test/analysis_test.dart rename pkgs/dart_services/test/{redis_cache_test.dart => caching_test.dart} (98%) delete mode 100644 pkgs/dart_services/test/common_server_api_protobuf_test.dart delete mode 100644 pkgs/dart_services/test/common_server_api_test.dart delete mode 100644 pkgs/dart_services/test/common_test.dart delete mode 100644 pkgs/dart_services/test/compiler_test.dart create mode 100644 pkgs/dart_services/test/compiling_test.dart delete mode 100644 pkgs/dart_services/test/flutter_analysis_server_test.dart delete mode 100644 pkgs/dart_services/test/gae_deployed_test.dart create mode 100644 pkgs/dart_services/test/src/sample_code.dart diff --git a/.github/workflows/dart_pad.yml b/.github/workflows/dart_pad.yml index 093be27d6..366af5a06 100644 --- a/.github/workflows/dart_pad.yml +++ b/.github/workflows/dart_pad.yml @@ -37,9 +37,6 @@ jobs: sdk: ${{ matrix.sdk }} - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 - - name: Install apt dependencies - run: sudo apt-get install -y protobuf-compiler - - name: Install dart dependencies run: dart pub get @@ -52,5 +49,4 @@ jobs: - name: Run buildbot run: | export PATH=$PATH:$HOME/.pub-cache/bin - dart pub global activate protoc_plugin dart run tool/grind.dart buildbot diff --git a/.github/workflows/dart_services.yml b/.github/workflows/dart_services.yml index 1e22e8605..091e46621 100644 --- a/.github/workflows/dart_services.yml +++ b/.github/workflows/dart_services.yml @@ -32,9 +32,6 @@ jobs: channel: ${{ matrix.sdk }} - run: flutter --version - - name: Install apt dependencies - run: sudo apt-get install -y protobuf-compiler redis - - name: Install dart dependencies run: dart pub get diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5e4e7a5f8..03dfee282 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,15 +42,12 @@ Contributions made by corporations are covered by a different agreement than the * To run the DartPad against the regular serving backend: -Install the [`protoc` compiler](https://grpc.io/docs/protoc-installation/). - Run these commands: ```bash # Get all Dart dependencies dart pub get -# Install the Dart protobuf compiler & grinder tool -dart pub global activate protoc_plugin +# Install the Dart grinder tool dart pub global activate grinder # Serve grind serve diff --git a/pkgs/dart_pad/pubspec.lock b/pkgs/dart_pad/pubspec.lock index df3b3263a..9c659c013 100644 --- a/pkgs/dart_pad/pubspec.lock +++ b/pkgs/dart_pad/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: archive - sha256: "7e0d52067d05f2e0324268097ba723b71cb41ac8a6a2b24d1edf9c536b987b03" + sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b" url: "https://pub.dev" source: hosted - version: "3.4.6" + version: "3.4.9" args: dependency: transitive description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.1" build_modules: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: "direct dev" description: name: build_web_compilers - sha256: "66a068988c1c409021a2fe646f428c362ab49021bbf2380b6965a34fbc90c8f8" + sha256: "70d67a571b068aa0b8f5569fea8f2d91647731643ad6d744f9035b47eefb2ace" url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "4.0.7" built_collection: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: built_value - sha256: a8de5955205b4d1dbbbc267daddf2178bd737e4bab8987c04a500478c9651e74 + sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e" url: "https://pub.dev" source: hosted - version: "8.6.3" + version: "8.7.0" charcode: dependency: transitive description: @@ -237,10 +237,10 @@ packages: dependency: transitive description: name: coverage - sha256: "595a29b55ce82d53398e1bcc2cba525d7bd7c59faeb2d2540e9d42c390cfeeeb" + sha256: ac86d3abab0f165e4b8f561280ff4e066bceaac83c424dd19f1ae2c2fcd12ca9 url: "https://pub.dev" source: hosted - version: "1.6.4" + version: "1.7.1" crypto: dependency: transitive description: @@ -316,10 +316,10 @@ packages: dependency: "direct main" description: name: fluttering_phrases - sha256: "8179cb8345756d2de2761516163e486eb5ac735eda61edefbd75caa14f2af969" + sha256: c9cbe31365e20cae3a21f4ba294d02c829fced712d2d6e7aad1a89b21db023a2 url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "1.0.0" frontend_server_client: dependency: transitive description: @@ -356,10 +356,10 @@ packages: dependency: "direct dev" description: name: grinder - sha256: "48495acdb3df702c55c952c6536faf11631b8401a292eb0d182ef332fc568b56" + sha256: e1996e485d2b56bb164a8585679758d488fbf567273f51c432c8733fee1f6188 url: "https://pub.dev" source: hosted - version: "0.9.4" + version: "0.9.5" html: dependency: transitive description: @@ -553,7 +553,7 @@ packages: source: hosted version: "1.5.1" protobuf: - dependency: "direct main" + dependency: transitive description: name: protobuf sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" @@ -588,10 +588,10 @@ packages: dependency: "direct overridden" description: name: sass - sha256: "5dd460578023d236404c3131cd7543399a891189aad130f61a16cc91f4842973" + sha256: "2b2bfbde0ccb493bc50520ab35a93821404dbec51f65e5f561ccdaf506cab50f" url: "https://pub.dev" source: hosted - version: "1.69.3" + version: "1.69.5" sass_builder: dependency: "direct main" description: @@ -739,10 +739,10 @@ packages: dependency: "direct dev" description: name: test - sha256: a20ddc0723556dc6dd56094e58ec1529196d5d7774156604cb14e8445a5a82ff + sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f url: "https://pub.dev" source: hosted - version: "1.24.7" + version: "1.24.9" test_api: dependency: transitive description: @@ -755,10 +755,10 @@ packages: dependency: transitive description: name: test_core - sha256: "96382d0bc826e260b077bb496259e58bc82e90b603ab16cd5ae95dfe1dfcba8b" + sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a url: "https://pub.dev" source: hosted - version: "0.5.7" + version: "0.5.9" test_process: dependency: transitive description: @@ -787,10 +787,10 @@ packages: dependency: transitive description: name: vm_service - sha256: a13d5503b4facefc515c8c587ce3cf69577a7b064a9f1220e005449cf1f64aad + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "12.0.0" + version: "13.0.0" watcher: dependency: transitive description: diff --git a/pkgs/dart_pad/pubspec.yaml b/pkgs/dart_pad/pubspec.yaml index 388d00093..53b43dc00 100644 --- a/pkgs/dart_pad/pubspec.yaml +++ b/pkgs/dart_pad/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: ^1.17.2 dartpad_shared: any encrypt: ^5.0.1 - fluttering_phrases: ^0.5.0 + fluttering_phrases: ^1.0.0 html_unescape: ^2.0.0 http: ^1.1.0 js: ^0.6.7 @@ -21,7 +21,6 @@ dependencies: mdc_web: ^0.6.0 meta: ^1.8.0 path: ^1.8.0 - protobuf: ^3.0.0 pub_semver: ^2.1.0 sass_builder: ^2.2.1 shelf: ^1.3.0 diff --git a/pkgs/dart_services/README.md b/pkgs/dart_services/README.md index e2c3c2561..f9dd465f4 100644 --- a/pkgs/dart_services/README.md +++ b/pkgs/dart_services/README.md @@ -19,22 +19,6 @@ This project is built with [grinder](https://pub.dev/packages/grinder). To insta $ dart pub global activate grinder ``` -The dart-services v2 API is defined in terms of Protobuf, which requires the -installation of the Protobuf `protoc` compiler. Please see [Protocol -Buffers](https://developers.google.com/protocol-buffers/) for detailed -installation instructions. On macOS, you may also install with Homebrew via: - -```bash -$ brew install protobuf -``` - -The Dart protoc plugin is also required for the above `protoc` compiler -to generate Dart code. To install, please run: - -```bash -$ dart pub global activate protoc_plugin -``` - ## Initialize Flutter The Flutter SDK needs to be downloaded and setup. diff --git a/pkgs/dart_services/lib/server.dart b/pkgs/dart_services/lib/server.dart index 49bfccd29..205c967e6 100644 --- a/pkgs/dart_services/lib/server.dart +++ b/pkgs/dart_services/lib/server.dart @@ -10,12 +10,11 @@ import 'package:logging/logging.dart'; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as shelf; -import 'src/common_server_api.dart'; -import 'src/common_server_impl.dart'; -import 'src/github_oauth_handler.dart'; +import 'src/caching.dart'; +import 'src/common_server.dart'; import 'src/logging.dart'; +import 'src/oauth_handler.dart'; import 'src/sdk.dart'; -import 'src/server_cache.dart'; final Logger _logger = Logger('services'); @@ -105,41 +104,53 @@ class EndpointsServer { late final Pipeline pipeline; late final Handler handler; - late final CommonServerApi commonServerApi; - late final CommonServerImpl _commonServerImpl; + late final CommonServerApi commonServer; EndpointsServer._(Sdk sdk, String? redisServerUri, String storageBucket) { // The name of the Cloud Run revision being run, for more detail please see: // https://cloud.google.com/run/docs/reference/container-contract#env-vars final serverVersion = Platform.environment['K_REVISION']; - _commonServerImpl = CommonServerImpl( + final cache = redisServerUri == null + ? NoopCache() + : RedisCache(redisServerUri, sdk, serverVersion); + + commonServer = CommonServerApi(CommonServerImpl( sdk, - redisServerUri == null - ? NoopCache() - : RedisCache(redisServerUri, sdk, serverVersion), + cache, storageBucket: storageBucket, - ); - commonServerApi = CommonServerApi(_commonServerImpl); + )); // Set cache for GitHub OAuth and add GitHub OAuth routes to our router. - GitHubOAuthHandler.setCache( - redisServerUri == null - ? InMemoryCache() - : RedisCache(redisServerUri, sdk, serverVersion), - ); - GitHubOAuthHandler.addRoutes(commonServerApi.router); + GitHubOAuthHandler.setCache(cache); + GitHubOAuthHandler.addRoutes(commonServer.router); pipeline = const Pipeline() .addMiddleware(logRequestsToLogger(_logger)) - .addMiddleware(createCustomCorsHeadersMiddleware()); + .addMiddleware(createCustomCorsHeadersMiddleware()) + .addMiddleware(exceptionResponse()); - handler = pipeline.addHandler(commonServerApi.router.call); + handler = pipeline.addHandler(commonServer.router.call); } - Future _init() => _commonServerImpl.init(); + Future _init() => commonServer.init(); int get port => server.port; - Future close() => server.close(); + Future close() async { + await commonServer.shutdown(); + await server.close(); + } +} + +Middleware exceptionResponse() { + return (Handler handler) { + return (Request request) async { + try { + return await handler(request); + } catch (e) { + return Response.badRequest(body: e is BadRequest ? e.message : '$e'); + } + }; + }; } diff --git a/pkgs/dart_services/lib/src/analysis.dart b/pkgs/dart_services/lib/src/analysis.dart new file mode 100644 index 000000000..4c6f4316e --- /dev/null +++ b/pkgs/dart_services/lib/src/analysis.dart @@ -0,0 +1,534 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// 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'; +import 'dart:io'; + +import 'package:analysis_server_lib/analysis_server_lib.dart'; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path; + +import 'common.dart'; +import 'common_server.dart'; +import 'project_templates.dart' as project; +import 'project_templates.dart'; +import 'pub.dart'; +import 'shared/model.dart' as api; +import 'utils.dart' as utils; + +final Logger _logger = Logger('analysis_server'); + +// todo: remove this class? +class AnalyzerWrapper { + final String dartSdkPath; + + late DartAnalysisServerWrapper _dartAnalysisServer; + + AnalyzerWrapper(this.dartSdkPath); + + Future init() async { + _logger.fine('Beginning AnalysisServersWrapper init().'); + _dartAnalysisServer = DartAnalysisServerWrapper(sdkPath: dartSdkPath); + await _dartAnalysisServer.init(); + _logger.info('Analysis server initialized.'); + + unawaited(_dartAnalysisServer.onExit.then((int code) { + _logger.severe('analysis server exited, code: $code'); + if (code != 0) { + exit(code); + } + })); + } + + // todo: inline this + Future analyze(String source) { + return _perfLogAndRestart( + source, + kMainDart, + 0, + (List imports, int? offset) => + _dartAnalysisServer.analyze(source, imports: imports), + 'analysis', + 'Error during analyze', + ); + } + + // todo: inline this + Future completeV3(String source, int offset) { + // todo: sanitize imports + return _dartAnalysisServer.completeV3(source, offset); + } + + // todo: inline this + Future fixesV3(String source, int offset) { + // todo: sanitize imports + return _dartAnalysisServer.fixesV3(source, offset); + } + + // todo: inline this + Future format(String source, int? offset) { + return _perfLogAndRestart( + source, + kMainDart, + offset, + (List imports, int? offset) => + _dartAnalysisServer.format(source, offset), + 'format', + 'Error during format at $offset', + ); + } + + // todo: inline this + Future dartdocV3(String source, int offset) { + // todo: sanitize imports + return _dartAnalysisServer.dartdocV3(source, offset); + } + + Future _perfLogAndRestart( + String source, + String activeSourceName, + int? offset, + Future Function(List, int?) body, + String action, + String errorDescription, + ) async { + final imports = getAllImportsFor(source); + await _checkPackageReferences(imports); + try { + final watch = Stopwatch()..start(); + final response = await body(imports, offset); + _logger.fine('PERF: Computed $action in ${watch.elapsedMilliseconds}ms.'); + return response; + } catch (e, st) { + _logger.severe(errorDescription, e, st); + rethrow; + } + } + + /// Check that the set of packages referenced is valid. + Future _checkPackageReferences(List imports) async { + final unsupportedImports = project.getUnsupportedImports( + imports, + sourcesFileList: [kMainDart], + ); + + if (unsupportedImports.isNotEmpty) { + // TODO(srawlins): Do the work so that each unsupported input is its own + // error, with a proper SourceSpan. + final unsupportedUris = + unsupportedImports.map((import) => import.uri.stringValue); + throw BadRequest('Unsupported import(s): $unsupportedUris'); + } + } + + Future shutdown() { + return _dartAnalysisServer.shutdown(); + } +} + +class DartAnalysisServerWrapper { + final String sdkPath; + final String projectPath; + + /// Instance to handle communication with the server. + late AnalysisServer analysisServer; + + DartAnalysisServerWrapper({ + required this.sdkPath, + String? projectPath, + }) : + // During analysis, we use the Firebase project template. The Firebase + // template is separate from the Flutter template only to keep Firebase + // references out of app initialization code at runtime. + projectPath = + projectPath ?? ProjectTemplates.projectTemplates.firebasePath; + + String get mainPath => _getPathFromName(kMainDart); + + Future init() async { + final serverArgs = ['--client-id=DartPad']; + _logger.info('Starting analysis server ' + '(sdk: ${path.relative(sdkPath)}, args: ${serverArgs.join(' ')})'); + + analysisServer = await AnalysisServer.create( + sdkPath: sdkPath, + serverArgs: serverArgs, + ); + + try { + analysisServer.server.onError.listen((ServerError error) { + _logger.severe('server error${error.isFatal ? ' (fatal)' : ''}', + error.message, StackTrace.fromString(error.stackTrace)); + }); + await analysisServer.server.onConnected.first; + await analysisServer.server.setSubscriptions(['STATUS']); + + listenForCompletions(); + + await analysisServer.analysis.setAnalysisRoots([projectPath], []); + } catch (err, st) { + _logger.severe('Error starting analysis server ($sdkPath): $err.\n$st'); + rethrow; + } + } + + Future get onExit { + // Return when the analysis server exits. We introduce a delay so that when + // we terminate the analysis server we can exit normally. + return analysisServer.processCompleter.future.then((int code) { + return Future.delayed(const Duration(seconds: 1), () { + return code; + }); + }); + } + + Future completeV3(String source, int offset) async { + final results = await _completeImpl( + {kMainDart: source}, + kMainDart, + offset, + ); + + final suggestions = + results.suggestions.where((CompletionSuggestion suggestion) { + // Filter suggestions that would require adding an import. + return suggestion.isNotImported != true; + }).where((CompletionSuggestion suggestion) { + if (suggestion.kind != 'IMPORT') return true; + + // todo: filter package suggestions to allowlisted packages + + // We do not want to enable arbitrary discovery of file system resources. + // In order to avoid returning local file paths, we only allow returning + // import kinds that are dart: or package: imports. + return suggestion.completion.startsWith('dart:') || + suggestion.completion.startsWith('package:'); + }).toList(); + + suggestions.sort((CompletionSuggestion x, CompletionSuggestion y) { + if (x.relevance == y.relevance) { + return x.completion.compareTo(y.completion); + } else { + return y.relevance.compareTo(x.relevance); + } + }); + + return api.CompleteResponse( + replacementOffset: results.replacementOffset, + replacementLength: results.replacementLength, + suggestions: suggestions.map((suggestion) { + return api.CompletionSuggestion( + kind: suggestion.kind, + relevance: suggestion.relevance, + completion: suggestion.completion, + deprecated: suggestion.isDeprecated, + selectionOffset: suggestion.selectionOffset, + displayText: suggestion.displayText, + parameterNames: suggestion.parameterNames, + returnType: suggestion.returnType, + elementKind: suggestion.element?.kind, + elementParameters: suggestion.element?.parameters, + ); + }).toList(), + ); + } + + Future fixesV3(String src, int offset) async { + final mainFile = _getPathFromName(kMainDart); + final overlay = {mainFile: src}; + + await _loadSources(overlay); + + try { + final fixes = await analysisServer.edit.getFixes(mainFile, offset); + final assists = await analysisServer.edit.getAssists(mainFile, offset, 1); + + final fixChanges = fixes.fixes.expand((fixes) => fixes.fixes).toList(); + final assistsChanges = assists.assists; + + // Filter any source changes that want to act on files other than main.dart. + fixChanges.removeWhere( + (change) => change.edits.any((edit) => edit.file != mainFile)); + assistsChanges.removeWhere( + (change) => change.edits.any((edit) => edit.file != mainFile)); + + return api.FixesResponse( + fixes: fixChanges.map((change) { + return change.toApiSourceChange(); + }).toList(), + assists: assistsChanges.map((change) { + return change.toApiSourceChange(); + }).toList(), + ); + } finally { + await _unloadSources(); + } + } + + /// Format the source [src] of the single passed in file. The [offset] is the + /// current cursor location and a modified offset is returned if necessary to + /// maintain the cursors original position in the formatted code. + Future format(String src, int? offset) { + return _formatImpl(src, offset).then((FormatResult editResult) { + final edits = editResult.edits; + + edits.sort((SourceEdit e1, SourceEdit e2) => + -1 * e1.offset.compareTo(e2.offset)); + + for (final edit in edits) { + src = src.replaceRange( + edit.offset, edit.offset + edit.length, edit.replacement); + } + + return api.FormatResponse( + source: src, + offset: offset == null ? 0 : editResult.selectionOffset, + ); + }).catchError((dynamic error) { + _logger.fine('format error: $error'); + return api.FormatResponse(source: src, offset: offset); + }); + } + + Future dartdocV3(String src, int offset) async { + final sources = _getOverlayMapWithPaths({kMainDart: src}); + final sourcepath = _getPathFromName(kMainDart); + + await _loadSources(sources); + + final result = await analysisServer.analysis.getHover(sourcepath, offset); + await _unloadSources(); + + if (result.hovers.isEmpty) { + return api.DocumentResponse(); + } + + final info = result.hovers.first; + + return api.DocumentResponse( + dartdoc: info.dartdoc, + containingLibraryName: info.containingLibraryName, + elementDescription: info.elementDescription, + elementKind: info.elementKind, + deprecated: info.isDeprecated, + propagatedType: info.propagatedType, + ); + } + + Future analyze( + String source, { + List? imports, + }) async { + final sources = _getOverlayMapWithPaths({kMainDart: source}); + await _loadSources(sources); + + final errors = []; + + // Loop over all files and collect errors. + for (final sourcepath in sources.keys) { + errors + .addAll((await analysisServer.analysis.getErrors(sourcepath)).errors); + } + await _unloadSources(); + + final issues = errors.map((error) { + final issue = api.AnalysisIssue( + kind: error.severity.toLowerCase(), + message: utils.normalizeFilePaths(error.message), + code: error.code.toLowerCase(), + location: api.Location( + charStart: error.location.offset, + charLength: error.location.length, + line: error.location.startLine, + column: error.location.startColumn, + ), + correction: error.correction == null + ? null + : utils.normalizeFilePaths(error.correction!), + url: error.url, + contextMessages: error.contextMessages?.map((m) { + return api.DiagnosticMessage( + message: utils.normalizeFilePaths(m.message), + location: api.Location( + charStart: m.location.offset, + charLength: m.location.length, + line: m.location.startLine, + column: m.location.startColumn, + ), + ); + }).toList(), + sourceName: path.basename(error.location.file), + ); + + return issue; + }).toList(); + + issues.sort((api.AnalysisIssue a, api.AnalysisIssue b) { + // Order issues by severity. + if (a.severity != b.severity) { + return b.severity - a.severity; + } + + // Then by character position. + return a.location.charStart.compareTo(b.location.charStart); + }); + + // Ensure we have imports if they were not passed in. + imports ??= getAllImportsFor(source); + + return api.AnalysisResponse( + issues: issues, + packageImports: filterSafePackages(imports), + ); + } + + /// Cleanly shutdown the Analysis Server. + Future shutdown() { + // TODO(jcollins-g): calling dispose() sometimes prevents + // --pause-isolates-on-exit from working; fix. + return analysisServer.server + .shutdown() + .timeout(const Duration(seconds: 1)) + // At runtime, it appears that [ServerDomain.shutdown] returns a + // `Future>`. + .catchError((_) => {}); + } + + Future _completeImpl( + Map sources, String sourceName, int offset) async { + sources = _getOverlayMapWithPaths(sources); + await _loadSources(sources); + + try { + return await analysisServer.completion.getSuggestions2( + _getPathFromName(sourceName), + offset, + 500, + ); + } finally { + // TODO: Remove the need to unload sources. + await _unloadSources(); + } + } + + Future _formatImpl(String src, int? offset) async { + await _loadSources({mainPath: src}); + final FormatResult result; + try { + result = await analysisServer.edit.format(mainPath, offset ?? 0, 0); + } finally { + await _unloadSources(); + } + return result; + } + + Map _getOverlayMapWithPaths(Map overlay) { + final newOverlay = {}; + for (final key in overlay.keys) { + newOverlay[_getPathFromName(key)] = overlay[key]!; + } + return newOverlay; + } + + String _getPathFromName(String sourceName) => + path.join(projectPath, sourceName); + + final Set _overlayPaths = {}; + + /// Loads [sources] as file system overlays to the analysis server. + /// + /// The analysis server then begins to analyze these as priority files. + Future _loadSources(Map sources) async { + if (_overlayPaths.isNotEmpty) { + throw StateError( + 'There should be no overlay paths while loading sources, but we ' + 'have: $_overlayPaths'); + } + await _sendAddOverlays(sources); + await analysisServer.analysis.setPriorityFiles(sources.keys.toList()); + } + + Future _unloadSources() async { + await _sendRemoveOverlays(); + await analysisServer.analysis.setPriorityFiles([]); + } + + /// Sends [overlays] to the analysis server. + Future _sendAddOverlays(Map overlays) async { + final contentOverlays = overlays.map((overlayPath, content) => + MapEntry(overlayPath, AddContentOverlay(content))); + + _logger.fine('About to send analysis.updateContent'); + _logger.fine(' ${contentOverlays.keys}'); + + _overlayPaths.addAll(contentOverlays.keys); + + await analysisServer.analysis.updateContent(contentOverlays); + } + + Future _sendRemoveOverlays() async { + _logger.fine('About to send analysis.updateContent remove overlays:'); + _logger.fine(' $_overlayPaths'); + + final contentOverlays = { + for (final overlayPath in _overlayPaths) + overlayPath: RemoveContentOverlay() + }; + _overlayPaths.clear(); + + await analysisServer.analysis.updateContent(contentOverlays); + } + + final Map> _completionCompleters = + >{}; + + void listenForCompletions() { + analysisServer.completion.onResults.listen((CompletionResults result) { + if (result.isLast) { + final completer = _completionCompleters.remove(result.id); + if (completer != null) { + completer.complete(result); + } + } + }); + } + + Future getCompletionResults(String id) { + final completer = Completer(); + _completionCompleters[id] = completer; + return completer.future; + } +} + +extension SourceChangeExtension on SourceChange { + api.SourceChange toApiSourceChange() { + return api.SourceChange( + message: message, + edits: edits + .expand((fileEdit) => fileEdit.edits) + .map( + (edit) => api.SourceEdit( + offset: edit.offset, + length: edit.length, + replacement: edit.replacement, + ), + ) + .toList(), + linkedEditGroups: linkedEditGroups.map((editGroup) { + return api.LinkedEditGroup( + offsets: editGroup.positions.map((pos) => pos.offset).toList(), + length: editGroup.length, + suggestions: editGroup.suggestions.map((sug) { + return api.LinkedEditSuggestion( + value: sug.value, + kind: sug.kind, + ); + }).toList(), + ); + }).toList(), + selectionOffset: selection?.offset, + ); + } +} diff --git a/pkgs/dart_services/lib/src/analysis_server.dart b/pkgs/dart_services/lib/src/analysis_server.dart deleted file mode 100644 index ad11c485e..000000000 --- a/pkgs/dart_services/lib/src/analysis_server.dart +++ /dev/null @@ -1,731 +0,0 @@ -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file -// 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. - -/// A wrapper around an analysis server instance -library; - -import 'dart:async'; -import 'dart:convert'; - -import 'package:analysis_server_lib/analysis_server_lib.dart'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:logging/logging.dart'; -import 'package:path/path.dart' as path; - -import 'common.dart'; -import 'project.dart'; -import 'protos/dart_services.pb.dart' as proto; -import 'pub.dart'; -import 'shared/model.dart' as api; -import 'utils.dart' as utils; - -final Logger _logger = Logger('analysis_server'); - -class DartAnalysisServerWrapper extends AnalysisServerWrapper { - DartAnalysisServerWrapper({required String dartSdkPath}) - // During analysis, we use the Firebase project template. The Firebase - // template is separate from the Flutter template only to keep Firebase - // references out of app initialization code at runtime. - : _sourceDirPath = ProjectTemplates.projectTemplates.firebasePath, - super(dartSdkPath); - - @override - final String _sourceDirPath; - - @override - String toString() => 'DartAnalysisServerWrapper<$_sourceDirPath>'; -} - -abstract class AnalysisServerWrapper { - final String sdkPath; - - bool _isInitialized = false; - - /// Instance to handle communication with the server. - late AnalysisServer analysisServer; - - AnalysisServerWrapper(this.sdkPath); - - String get mainPath => _getPathFromName(kMainDart); - - String get _sourceDirPath; - - Future init() async { - if (_isInitialized) { - throw StateError('AnalysisServerWrapper is already initialized'); - } - - _isInitialized = true; - - final serverArgs = ['--client-id=DartPad']; - _logger.info('Starting analysis server ' - '(sdk: ${path.relative(sdkPath)}, args: ${serverArgs.join(' ')})'); - - analysisServer = await AnalysisServer.create( - sdkPath: sdkPath, - serverArgs: serverArgs, - ); - - try { - analysisServer.server.onError.listen((ServerError error) { - _logger.severe('server error${error.isFatal ? ' (fatal)' : ''}', - error.message, StackTrace.fromString(error.stackTrace)); - }); - await analysisServer.server.onConnected.first; - await analysisServer.server.setSubscriptions(['STATUS']); - - listenForCompletions(); - - await analysisServer.analysis.setAnalysisRoots([_sourceDirPath], []); - } catch (err, st) { - _logger.severe('Error starting analysis server ($sdkPath): $err.\n$st'); - rethrow; - } - } - - Future get onExit { - // Return when the analysis server exits. We introduce a delay so that when - // we terminate the analysis server we can exit normally. - return analysisServer.processCompleter.future.then((int code) { - return Future.delayed(const Duration(seconds: 1), () { - return code; - }); - }); - } - - Future complete(String src, int offset) async { - return completeFiles({kMainDart: src}, Location(kMainDart, offset)); - } - - Future completeFiles( - Map sources, Location location) async { - final results = - await _completeImpl(sources, location.sourceName, location.offset!); - var suggestions = results.results; - - final source = sources[location.sourceName]!; - final prefix = source.substring(results.replacementOffset, location.offset); - suggestions = suggestions.where((suggestion) { - return suggestion.completion - .toLowerCase() - .startsWith(prefix.toLowerCase()); - }).where((CompletionSuggestion suggestion) { - // We do not want to enable arbitrary discovery of file system resources. - - // In order to avoid returning local file paths, we only allow returning - // IMPORT kinds that are dart: or package: imports. - if (suggestion.kind == 'IMPORT') { - final completion = suggestion.completion; - return completion.startsWith('dart:') || - completion.startsWith('package:'); - } else { - return true; - } - }).toList(); - - suggestions.sort((CompletionSuggestion x, CompletionSuggestion y) { - if (x.relevance == y.relevance) { - return x.completion.compareTo(y.completion); - } else { - return y.relevance.compareTo(x.relevance); - } - }); - - return proto.CompleteResponse() - ..replacementOffset = results.replacementOffset - ..replacementLength = results.replacementLength - ..completions - .addAll(suggestions.map((CompletionSuggestion c) => proto.Completion() - ..completion.addAll(c.toMap().map((key, value) { - // TODO: Properly support Lists, Maps (this is a hack). - if (value is Map || value is List) { - value = json.encode(value); - } - return MapEntry(key.toString(), value.toString()); - })))); - } - - Future completeV3(String source, int offset) async { - final results = await _completeImpl2( - {kMainDart: source}, - kMainDart, - offset, - ); - - final suggestions = - results.suggestions.where((CompletionSuggestion suggestion) { - // Filter suggestions that would require adding an import. - return suggestion.isNotImported != true; - }).where((CompletionSuggestion suggestion) { - if (suggestion.kind != 'IMPORT') return true; - - // We do not want to enable arbitrary discovery of file system resources. - // In order to avoid returning local file paths, we only allow returning - // import kinds that are dart: or package: imports. - return suggestion.completion.startsWith('dart:') || - suggestion.completion.startsWith('package:'); - }).toList(); - - suggestions.sort((CompletionSuggestion x, CompletionSuggestion y) { - if (x.relevance == y.relevance) { - return x.completion.compareTo(y.completion); - } else { - return y.relevance.compareTo(x.relevance); - } - }); - - return api.CompleteResponse( - replacementOffset: results.replacementOffset, - replacementLength: results.replacementLength, - suggestions: suggestions.map((suggestion) { - return api.CompletionSuggestion( - kind: suggestion.kind, - relevance: suggestion.relevance, - completion: suggestion.completion, - deprecated: suggestion.isDeprecated, - selectionOffset: suggestion.selectionOffset, - displayText: suggestion.displayText, - parameterNames: suggestion.parameterNames, - returnType: suggestion.returnType, - elementKind: suggestion.element?.kind, - elementParameters: suggestion.element?.parameters, - ); - }).toList(), - ); - } - - Future getFixes(String src, int offset) { - return getFixesMulti({kMainDart: src}, Location(kMainDart, offset)); - } - - Future getFixesMulti( - Map sources, Location location) async { - final results = - await _getFixesImpl(sources, location.sourceName, location.offset!); - final responseFixes = results.fixes.map((availableAnalysisErrorFixes) { - return _convertAnalysisErrorFix( - availableAnalysisErrorFixes, location.sourceName); - }); - return proto.FixesResponse()..fixes.addAll(responseFixes); - } - - Future fixesV3(String src, int offset) async { - final mainFile = _getPathFromName(kMainDart); - final overlay = {mainFile: src}; - - await _loadSources(overlay); - - try { - final fixes = await analysisServer.edit.getFixes(mainFile, offset); - final assists = await analysisServer.edit.getAssists(mainFile, offset, 1); - - final fixChanges = fixes.fixes.expand((fixes) => fixes.fixes).toList(); - final assistsChanges = assists.assists; - - // Filter any source changes that want to act on files other than main.dart. - fixChanges.removeWhere( - (change) => change.edits.any((edit) => edit.file != mainFile)); - assistsChanges.removeWhere( - (change) => change.edits.any((edit) => edit.file != mainFile)); - - return api.FixesResponse( - fixes: fixChanges.map((change) { - return change.toApiSourceChange(); - }).toList(), - assists: assistsChanges.map((change) { - return change.toApiSourceChange(); - }).toList(), - ); - } finally { - await _unloadSources(); - } - } - - Future getAssists(String src, int offset) async { - return getAssistsMulti({kMainDart: src}, Location(kMainDart, offset)); - } - - Future getAssistsMulti( - Map sources, Location location) async { - final sourceName = location.sourceName; - final results = - await _getAssistsImpl(sources, sourceName, location.offset!); - final fixes = - _convertSourceChangesToCandidateFixes(results.assists, sourceName); - return proto.AssistsResponse()..assists.addAll(fixes); - } - - /// Format the source [src] of the single passed in file. The [offset] is - /// the current cursor location and a modified offset is returned if necessary - /// to maintain the cursors original position in the formatted code. - Future format(String src, int? offset) { - return _formatImpl(src, offset).then((FormatResult editResult) { - final edits = editResult.edits; - - edits.sort((SourceEdit e1, SourceEdit e2) => - -1 * e1.offset.compareTo(e2.offset)); - - for (final edit in edits) { - src = src.replaceRange( - edit.offset, edit.offset + edit.length, edit.replacement); - } - - return proto.FormatResponse() - ..newString = src - ..offset = offset == null ? 0 : editResult.selectionOffset; - }).catchError((dynamic error) { - _logger.fine('format error: $error'); - return proto.FormatResponse() - ..newString = src - ..offset = offset ?? 0; - }); - } - - Future> dartdoc(String src, int offset) { - return dartdocMulti({kMainDart: src}, Location(kMainDart, offset)); - } - - Future> dartdocMulti( - Map sources, Location location) async { - sources = _getOverlayMapWithPaths(sources); - final sourcepath = _getPathFromName(location.sourceName); - - await _loadSources(sources); - - final result = - await analysisServer.analysis.getHover(sourcepath, location.offset); - await _unloadSources(); - - if (result.hovers.isEmpty) { - return const {}; - } - - final info = result.hovers.first; - - return { - if (info.elementDescription != null) - 'description': info.elementDescription!, - if (info.elementKind != null) 'kind': info.elementKind!, - if (info.dartdoc != null) 'dartdoc': info.dartdoc!, - if (info.containingClassDescription != null) - 'enclosingClassName': info.containingClassDescription!, - if (info.containingLibraryName != null) - 'libraryName': info.containingLibraryName!, - if (info.parameter != null) 'parameter': info.parameter!, - if (info.isDeprecated != null) - 'deprecated': info.isDeprecated!.toString(), - if (info.staticType != null) 'staticType': info.staticType!, - if (info.propagatedType != null) 'propagatedType': info.propagatedType!, - }; - } - - Future dartdocV3(String src, int offset) async { - final location = Location(kMainDart, offset); - final sources = _getOverlayMapWithPaths({kMainDart: src}); - final sourcepath = _getPathFromName(location.sourceName); - - await _loadSources(sources); - - final result = - await analysisServer.analysis.getHover(sourcepath, location.offset); - await _unloadSources(); - - if (result.hovers.isEmpty) { - return api.DocumentResponse(); - } - - final info = result.hovers.first; - - return api.DocumentResponse( - dartdoc: info.dartdoc, - containingLibraryName: info.containingLibraryName, - elementDescription: info.elementDescription, - elementKind: info.elementKind, - deprecated: info.isDeprecated, - propagatedType: info.propagatedType, - ); - } - - Future analyze(String src) { - return analyzeFiles({kMainDart: src}); - } - - Future analyzeFiles(Map sources, - {List? imports}) async { - sources = _getOverlayMapWithPaths(sources); - await _loadSources(sources); - final errors = []; - - // Loop over all files and collect errors (sources now has filenames - // with full paths as keys after _getOverlayMapWithPaths() call). - for (final sourcepath in sources.keys) { - errors - .addAll((await analysisServer.analysis.getErrors(sourcepath)).errors); - } - await _unloadSources(); - - // Convert the issues to protos. - final issues = errors.map((error) { - final issue = proto.AnalysisIssue() - ..kind = error.severity.toLowerCase() - ..code = error.code.toLowerCase() - ..line = error.location.startLine - ..column = error.location.startColumn - ..message = utils.normalizeFilePaths(error.message) - ..sourceName = path.basename(error.location.file) - ..hasFixes = error.hasFix ?? false - ..charStart = error.location.offset - ..charLength = error.location.length - ..diagnosticMessages.addAll( - error.contextMessages?.map((m) => proto.DiagnosticMessage() - ..message = utils.normalizeFilePaths(m.message) - ..line = m.location.startLine - ..column = m.location.startColumn - ..charStart = m.location.offset - ..charLength = m.location.length) ?? - [], - ); - - if (error.url != null) { - issue.url = error.url!; - } - - if (error.correction != null) { - issue.correction = utils.normalizeFilePaths(error.correction!); - } - - return issue; - }).toList(); - - issues.sort((proto.AnalysisIssue a, proto.AnalysisIssue b) { - // Order issues by severity. - if (a.severity != b.severity) { - return b.severity - a.severity; - } - - // Then by character position. - return a.charStart.compareTo(b.charStart); - }); - - // Ensure we have imports if they were not passed in. - imports ??= getAllImportsForFiles(sources); - - // Calculate the package: imports (and defensively sanitize). - final packageImports = { - ...imports.filterSafePackages(), - }; - - return proto.AnalysisResults() - ..issues.addAll(issues) - ..packageImports.addAll(packageImports); - } - - Future _getAssistsImpl( - Map sources, String sourceName, int offset) async { - sources = _getOverlayMapWithPaths(sources); - final path = _getPathFromName(sourceName); - - await _loadSources(sources); - final AssistsResult assists; - try { - assists = - await analysisServer.edit.getAssists(path, offset, 1 /* length */); - } finally { - await _unloadSources(); - } - return assists; - } - - /// Convert between the Analysis Server type and the API protocol types. - static proto.ProblemAndFixes _convertAnalysisErrorFix( - AnalysisErrorFixes analysisFixes, String filename) { - final problemMessage = analysisFixes.error.message; - final problemOffset = analysisFixes.error.location.offset; - final problemLength = analysisFixes.error.location.length; - - final possibleFixes = []; - - for (final sourceChange in analysisFixes.fixes) { - final edits = []; - - // A fix that tries to modify other files is considered invalid. - - var invalidFix = false; - for (final sourceFileEdit in sourceChange.edits) { - // TODO(lukechurch): replace this with a more reliable test based on the - // psuedo file name in Analysis Server - if (!sourceFileEdit.file.endsWith('/$filename')) { - invalidFix = true; - break; - } - - for (final sourceEdit in sourceFileEdit.edits) { - edits.add(proto.SourceEdit() - ..offset = sourceEdit.offset - ..length = sourceEdit.length - ..replacement = sourceEdit.replacement); - } - } - if (!invalidFix) { - final possibleFix = proto.CandidateFix() - ..message = sourceChange.message - ..edits.addAll(edits); - possibleFixes.add(possibleFix); - } - } - return proto.ProblemAndFixes() - ..fixes.addAll(possibleFixes) - ..problemMessage = problemMessage - ..offset = problemOffset - ..length = problemLength; - } - - static List _convertSourceChangesToCandidateFixes( - List sourceChanges, String filename) { - final assists = []; - - for (final sourceChange in sourceChanges) { - for (final sourceFileEdit in sourceChange.edits) { - if (!sourceFileEdit.file.endsWith('/$filename')) { - break; - } - - final sourceEdits = sourceFileEdit.edits.map((sourceEdit) { - return proto.SourceEdit() - ..offset = sourceEdit.offset - ..length = sourceEdit.length - ..replacement = sourceEdit.replacement; - }); - - final candidateFix = proto.CandidateFix(); - candidateFix.message = sourceChange.message; - candidateFix.edits.addAll(sourceEdits); - final selectionOffset = sourceChange.selection?.offset; - if (selectionOffset != null) { - candidateFix.selectionOffset = selectionOffset; - } - candidateFix.linkedEditGroups - .addAll(_convertLinkedEditGroups(sourceChange.linkedEditGroups)); - assists.add(candidateFix); - } - } - - return assists; - } - - /// Convert a list of the analysis server's [LinkedEditGroup]s into the API's - /// equivalent. - static Iterable _convertLinkedEditGroups( - Iterable groups) { - return groups.map((g) { - return proto.LinkedEditGroup() - ..positions.addAll(g.positions.map((p) => p.offset).toList()) - ..length = g.length - ..suggestions.addAll(g.suggestions - .map((s) => proto.LinkedEditSuggestion() - ..value = s.value - ..kind = s.kind) - .toList()); - }); - } - - /// Cleanly shutdown the Analysis Server. - Future shutdown() { - // TODO(jcollins-g): calling dispose() sometimes prevents - // --pause-isolates-on-exit from working; fix. - return analysisServer.server - .shutdown() - .timeout(const Duration(seconds: 1)) - // At runtime, it appears that [ServerDomain.shutdown] returns a - // `Future>`. - .catchError((_) => {}); - } - - /// Internal implementation of the completion mechanism. - Future _completeImpl( - Map sources, String sourceName, int offset) async { - sources = _getOverlayMapWithPaths(sources); - await _loadSources(sources); - final id = await analysisServer.completion.getSuggestions( - _getPathFromName(sourceName), - offset, - ); - final CompletionResults results; - try { - results = await getCompletionResults(id.id); - } finally { - await _unloadSources(); - } - return results; - } - - Future _completeImpl2( - Map sources, String sourceName, int offset) async { - sources = _getOverlayMapWithPaths(sources); - await _loadSources(sources); - - try { - return await analysisServer.completion.getSuggestions2( - _getPathFromName(sourceName), - offset, - 500, - ); - } finally { - // TODO: Remove the need to unload sources. - await _unloadSources(); - } - } - - Future _getFixesImpl( - Map sources, String sourceName, int offset) async { - sources = _getOverlayMapWithPaths(sources); - final path = _getPathFromName(sourceName); - - await _loadSources(sources); - final FixesResult fixes; - try { - fixes = await analysisServer.edit.getFixes(path, offset); - } finally { - await _unloadSources(); - } - return fixes; - } - - Future _formatImpl(String src, int? offset) async { - await _loadSources({mainPath: src}); - final FormatResult result; - try { - result = await analysisServer.edit.format(mainPath, offset ?? 0, 0); - } finally { - await _unloadSources(); - } - return result; - } - - Map _getOverlayMapWithPaths(Map overlay) { - final newOverlay = {}; - for (final key in overlay.keys) { - newOverlay[_getPathFromName(key)] = overlay[key]!; - } - return newOverlay; - } - - String _getPathFromName(String sourceName) => - path.join(_sourceDirPath, sourceName); - - final Set _overlayPaths = {}; - - /// Loads [sources] as file system overlays to the analysis server. - /// - /// The analysis server then begins to analyze these as priority files. - Future _loadSources(Map sources) async { - if (_overlayPaths.isNotEmpty) { - throw StateError( - 'There should be no overlay paths while loading sources, but we ' - 'have: $_overlayPaths'); - } - await _sendAddOverlays(sources); - await analysisServer.analysis.setPriorityFiles(sources.keys.toList()); - } - - Future _unloadSources() async { - await _sendRemoveOverlays(); - await analysisServer.analysis.setPriorityFiles([]); - } - - /// Sends [overlays] to the analysis server. - Future _sendAddOverlays(Map overlays) async { - final contentOverlays = overlays.map((overlayPath, content) => - MapEntry(overlayPath, AddContentOverlay(content))); - - _logger.fine('About to send analysis.updateContent'); - _logger.fine(' ${contentOverlays.keys}'); - - _overlayPaths.addAll(contentOverlays.keys); - - await analysisServer.analysis.updateContent(contentOverlays); - } - - Future _sendRemoveOverlays() async { - _logger.fine('About to send analysis.updateContent remove overlays:'); - _logger.fine(' $_overlayPaths'); - - final contentOverlays = { - for (final overlayPath in _overlayPaths) - overlayPath: RemoveContentOverlay() - }; - _overlayPaths.clear(); - - await analysisServer.analysis.updateContent(contentOverlays); - } - - final Map> _completionCompleters = - >{}; - - void listenForCompletions() { - analysisServer.completion.onResults.listen((CompletionResults result) { - if (result.isLast) { - final completer = _completionCompleters.remove(result.id); - if (completer != null) { - completer.complete(result); - } - } - }); - } - - Future getCompletionResults(String id) { - final completer = Completer(); - _completionCompleters[id] = completer; - return completer.future; - } -} - -class Location { - final String sourceName; - final int? offset; - - const Location(this.sourceName, this.offset); -} - -extension SourceChangeExtension on SourceChange { - api.SourceChange toApiSourceChange() { - return api.SourceChange( - message: message, - edits: edits - .expand((fileEdit) => fileEdit.edits) - .map( - (edit) => api.SourceEdit( - offset: edit.offset, - length: edit.length, - replacement: edit.replacement, - ), - ) - .toList(), - linkedEditGroups: linkedEditGroups.map((editGroup) { - return api.LinkedEditGroup( - offsets: editGroup.positions.map((pos) => pos.offset).toList(), - length: editGroup.length, - suggestions: editGroup.suggestions.map((sug) { - return api.LinkedEditSuggestion( - value: sug.value, - kind: sug.kind, - ); - }).toList(), - ); - }).toList(), - selectionOffset: selection?.offset, - ); - } -} - -extension AnalysisIssueExtension on proto.AnalysisIssue { - int get severity { - return switch (kind) { - 'error' => 3, - 'warning' => 2, - 'info' => 1, - _ => 0, - }; - } -} diff --git a/pkgs/dart_services/lib/src/analyzer_wrapper.dart b/pkgs/dart_services/lib/src/analyzer_wrapper.dart deleted file mode 100644 index 9ff7dc324..000000000 --- a/pkgs/dart_services/lib/src/analyzer_wrapper.dart +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// 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. - -/// A wrapper around an analysis server instance. -library; - -import 'dart:async'; -import 'dart:io'; - -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:logging/logging.dart'; - -import 'analysis_server.dart'; -import 'common.dart'; -import 'common_server_impl.dart' show BadRequest; -import 'project.dart' as project; -import 'protos/dart_services.pb.dart' as proto; -import 'pub.dart'; -import 'shared/model.dart' as api; - -final Logger _logger = Logger('analysis_servers'); - -class AnalyzerWrapper { - final String _dartSdkPath; - - AnalyzerWrapper(this._dartSdkPath); - - late DartAnalysisServerWrapper _dartAnalysisServer; - - // If non-null, this value indicates that the server is starting/restarting - // and holds the time at which that process began. If null, the server is - // ready to handle requests. - DateTime? _restartingSince = DateTime.now(); - - bool get isRestarting => _restartingSince != null; - - // If the server has been trying and failing to restart for more than a half - // hour, something is seriously wrong. - bool get isHealthy => - _restartingSince == null || - DateTime.now().difference(_restartingSince!).inMinutes < 30; - - Future init() async { - _logger.fine('Beginning AnalysisServersWrapper init().'); - _dartAnalysisServer = DartAnalysisServerWrapper(dartSdkPath: _dartSdkPath); - await _dartAnalysisServer.init(); - _logger.info('Analysis server initialized.'); - - unawaited(_dartAnalysisServer.onExit.then((int code) { - _logger.severe('analysis server exited, code: $code'); - if (code != 0) { - exit(code); - } - })); - - _restartingSince = null; - } - - Future _restart() async { - _logger.warning('Restarting'); - await shutdown(); - _logger.info('shutdown'); - - await init(); - _logger.warning('Restart complete'); - } - - Future shutdown() { - _restartingSince = DateTime.now(); - - return _dartAnalysisServer.shutdown(); - } - - Future analyze(String source) => - analyzeFiles({kMainDart: source}, kMainDart); - - Future analyzeFiles( - Map sources, String activeSourceName) => - _perfLogAndRestart( - sources, - activeSourceName, - 0, - (List imports, Location location) => - _dartAnalysisServer.analyzeFiles(sources, imports: imports), - 'analysis', - 'Error during analyze on "${sources[activeSourceName]}"'); - - Future complete(String source, int offset) => - completeFiles({kMainDart: source}, kMainDart, offset); - - Future completeFiles( - Map sources, String activeSourceName, int offset) => - _perfLogAndRestart( - sources, - activeSourceName, - offset, - (List imports, Location location) => - _dartAnalysisServer.completeFiles(sources, location), - 'completions', - 'Error during complete on "${sources[activeSourceName]}" at $offset', - ); - - Future completeV3(String source, int offset) { - return _dartAnalysisServer.completeV3(source, offset); - } - - Future getFixes(String source, int offset) => - getFixesMulti({kMainDart: source}, kMainDart, offset); - - Future getFixesMulti( - Map sources, String activeSourceName, int offset) => - _perfLogAndRestart( - sources, - activeSourceName, - offset, - (List imports, Location location) => - _dartAnalysisServer.getFixesMulti(sources, location), - 'fixes', - 'Error during fixes on "${sources[activeSourceName]}" at $offset', - ); - - Future fixesV3(String source, int offset) => - _dartAnalysisServer.fixesV3(source, offset); - - Future getAssists(String source, int offset) => - getAssistsMulti({kMainDart: source}, kMainDart, offset); - - Future getAssistsMulti( - Map sources, String activeSourceName, int offset) => - _perfLogAndRestart( - sources, - activeSourceName, - offset, - (List imports, Location location) => - _dartAnalysisServer.getAssistsMulti(sources, location), - 'assists', - 'Error during assists on "${sources[activeSourceName]}" at $offset', - ); - - Future format(String source, int? offset) { - return _perfLogAndRestart( - {kMainDart: source}, - kMainDart, - offset, - (List imports, Location _) => - _dartAnalysisServer.format(source, offset), - 'format', - 'Error during format at $offset', - ); - } - - Future> dartdoc(String source, int offset) => - dartdocMulti({kMainDart: source}, kMainDart, offset); - - Future> dartdocMulti( - Map sources, String activeSourceName, int offset) => - _perfLogAndRestart( - sources, - activeSourceName, - offset, - (List imports, Location location) => - _dartAnalysisServer.dartdocMulti(sources, location), - 'dartdoc', - 'Error during dartdoc on "${sources[activeSourceName]}" at $offset', - ); - - Future dartdocV3(String source, int offset) { - return _dartAnalysisServer.dartdocV3(source, offset); - } - - Future _perfLogAndRestart( - Map sources, - String activeSourceName, - int? offset, - Future Function(List, Location) body, - String action, - String errorDescription, - ) async { - activeSourceName = sanitizeAndCheckFilenames(sources, activeSourceName); - final imports = getAllImportsForFiles(sources); - final location = Location(activeSourceName, offset); - await _checkPackageReferences(sources, imports); - try { - final watch = Stopwatch()..start(); - final response = await body(imports, location); - _logger.fine('PERF: Computed $action in ${watch.elapsedMilliseconds}ms.'); - return response; - } catch (e, st) { - _logger.severe(errorDescription, e, st); - await _restart(); - rethrow; - } - } - - /// Check that the set of packages referenced is valid. - Future _checkPackageReferences( - Map sources, - List imports, - ) async { - final unsupportedImports = project.getUnsupportedImports(imports, - sourcesFileList: sources.keys.toList()); - - if (unsupportedImports.isNotEmpty) { - // TODO(srawlins): Do the work so that each unsupported input is its own - // error, with a proper SourceSpan. - final unsupportedUris = - unsupportedImports.map((import) => import.uri.stringValue); - throw BadRequest('Unsupported import(s): $unsupportedUris'); - } - } -} diff --git a/pkgs/dart_services/lib/src/server_cache.dart b/pkgs/dart_services/lib/src/caching.dart similarity index 99% rename from pkgs/dart_services/lib/src/server_cache.dart rename to pkgs/dart_services/lib/src/caching.dart index 59d4a5163..bbf274b81 100644 --- a/pkgs/dart_services/lib/src/server_cache.dart +++ b/pkgs/dart_services/lib/src/caching.dart @@ -5,13 +5,15 @@ import 'dart:async'; import 'dart:math'; +import 'package:logging/logging.dart'; import 'package:resp_client/resp_client.dart'; import 'package:resp_client/resp_commands.dart'; import 'package:resp_client/resp_server.dart'; -import 'common_server_impl.dart' show log; import 'sdk.dart'; +final Logger log = Logger('caching'); + abstract class ServerCache { Future get(String key); diff --git a/pkgs/dart_services/lib/src/common.dart b/pkgs/dart_services/lib/src/common.dart index 54d6444a8..fe9bc5c90 100644 --- a/pkgs/dart_services/lib/src/common.dart +++ b/pkgs/dart_services/lib/src/common.dart @@ -3,8 +3,17 @@ // BSD-style license that can be found in the LICENSE file. const kMainDart = 'main.dart'; + const kBootstrapDart = 'bootstrap.dart'; +const kBootstrapDartCode = r''' +import 'main.dart' as user_code; + +void main() { + user_code.main(); +} +'''; + // This code should be kept up-to-date with // https://github.com/flutter/flutter/blob/master/packages/flutter_tools/lib/src/web/bootstrap.dart#L236. const kBootstrapFlutterCode = r''' @@ -36,869 +45,3 @@ Future main() async { entrypoint.main(); } '''; - -const kBootstrapDartCode = r''' -import 'main.dart' as user_code; - -void main() { - user_code.main(); -} -'''; - -const sampleCode = ''' -void main() { - print("hello"); -} -'''; - -const sampleCodeWeb = """ -import 'dart:html'; - -void main() { - print("hello"); - querySelector('#foo')?.text = 'bar'; -} -"""; - -const sampleCodeFlutter = ''' -import 'package:flutter/material.dart'; - -void main() async { - runApp( - MaterialApp( - debugShowCheckedModeBanner: false, - home: Scaffold( - appBar: AppBar( - title: const Text('Hello, World!'), - ), - body: const Center( - child: Text( - 'Hello, World!', - ), - ), - ), - ), - ); -} -'''; - -// From https://gist.github.com/johnpryan/1a28bdd9203250d3226cc25d512579ec -const sampleCodeFlutterCounter = r''' -import 'package:flutter/material.dart'; - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - debugShowCheckedModeBanner: false, - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), - ); - } -} - -class MyHomePage extends StatefulWidget { - final String title; - const MyHomePage({ - super.key, - required this.title, - }); - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), - ), - ); - } -} -'''; - -// From https://gist.github.com/RedBrogdon/e0a2e942e85fde2cd39b2741ff0c49e5 -const sampleCodeFlutterSunflower = r''' -import 'dart:math' as math; -import 'package:flutter/material.dart'; - -const Color primaryColor = Colors.orange; -const TargetPlatform platform = TargetPlatform.android; - -void main() { - runApp(Sunflower()); -} - -class SunflowerPainter extends CustomPainter { - static const seedRadius = 2.0; - static const scaleFactor = 4; - static const tau = math.pi * 2; - - static final phi = (math.sqrt(5) + 1) / 2; - - final int seeds; - - SunflowerPainter(this.seeds); - - @override - void paint(Canvas canvas, Size size) { - final center = size.width / 2; - - for (var i = 0; i < seeds; i++) { - final theta = i * tau / phi; - final r = math.sqrt(i) * scaleFactor; - final x = center + r * math.cos(theta); - final y = center - r * math.sin(theta); - final offset = Offset(x, y); - if (!size.contains(offset)) { - continue; - } - drawSeed(canvas, x, y); - } - } - - @override - bool shouldRepaint(SunflowerPainter oldDelegate) { - return oldDelegate.seeds != seeds; - } - - // Draw a small circle representing a seed centered at (x,y). - void drawSeed(Canvas canvas, double x, double y) { - final paint = Paint() - ..strokeWidth = 2 - ..style = PaintingStyle.fill - ..color = primaryColor; - canvas.drawCircle(Offset(x, y), seedRadius, paint); - } -} - -class Sunflower extends StatefulWidget { - @override - State createState() { - return _SunflowerState(); - } -} - -class _SunflowerState extends State { - double seeds = 100.0; - - int get seedCount => seeds.floor(); - - @override - Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData().copyWith( - platform: platform, - brightness: Brightness.dark, - sliderTheme: SliderThemeData.fromPrimaryColors( - primaryColor: primaryColor, - primaryColorLight: primaryColor, - primaryColorDark: primaryColor, - valueIndicatorTextStyle: const DefaultTextStyle.fallback().style, - ), - ), - home: Scaffold( - appBar: AppBar(title: const Text("Sunflower")), - drawer: Drawer( - child: ListView( - children: const [ - DrawerHeader( - child: Center( - child: Text( - "Sunflower 🌻", - style: TextStyle(fontSize: 32), - ), - ), - ), - ], - )), - body: Container( - constraints: const BoxConstraints.expand(), - decoration: - BoxDecoration(border: Border.all(color: Colors.transparent)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.transparent)), - child: SizedBox( - width: 400, - height: 400, - child: CustomPaint( - painter: SunflowerPainter(seedCount), - ), - ), - ), - Text("Showing $seedCount seeds"), - ConstrainedBox( - constraints: const BoxConstraints.tightFor(width: 300), - child: Slider.adaptive( - min: 20, - max: 2000, - value: seeds, - onChanged: (newValue) { - setState(() { - seeds = newValue; - }); - }, - ), - ), - ], - ), - ), - ), - ); - } -} -'''; - -// https://gist.github.com/johnpryan/5e28c5273c2c1a41d30bad9f9d11da56 -const sampleCodeFlutterDraggableCard = ''' -import 'package:flutter/material.dart'; -import 'package:flutter/physics.dart'; - -main() { - runApp( - MaterialApp( - debugShowCheckedModeBanner: false, - home: PhysicsCardDragDemo(), - ), - ); -} - -class PhysicsCardDragDemo extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('A draggable card!'), - ), - body: const DraggableCard( - child: FlutterLogo( - size: 128, - ), - ), - ); - } -} - -class DraggableCard extends StatefulWidget { - final Widget child; - const DraggableCard({required this.child}); - - @override - State createState() => _DraggableCardState(); -} - -class _DraggableCardState extends State - with SingleTickerProviderStateMixin { - AnimationController? _controller; - Alignment _dragAlignment = Alignment.center; - Animation? _animation; - - void _runAnimation(Offset pixelsPerSecond, Size size) { - _animation = _controller!.drive( - AlignmentTween( - begin: _dragAlignment, - end: Alignment.center, - ), - ); - - final unitsPerSecondX = pixelsPerSecond.dx / size.width; - final unitsPerSecondY = pixelsPerSecond.dy / size.height; - final unitsPerSecond = Offset(unitsPerSecondX, unitsPerSecondY); - final unitVelocity = unitsPerSecond.distance; - - const spring = SpringDescription( - mass: 30, - stiffness: 1, - damping: 1, - ); - - final simulation = SpringSimulation(spring, 0, 1, -unitVelocity); - - _controller!.animateWith(simulation); - } - - @override - void initState() { - super.initState(); - _controller = AnimationController(vsync: this); - - _controller!.addListener(() { - setState(() { - _dragAlignment = _animation!.value; - }); - }); - } - - @override - void dispose() { - _controller!.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final size = MediaQuery.of(context).size; - return GestureDetector( - onPanDown: (details) { - _controller!.stop(); - }, - onPanUpdate: (details) { - setState(() { - _dragAlignment += Alignment( - details.delta.dx / (size.width / 2), - details.delta.dy / (size.height / 2), - ); - }); - }, - onPanEnd: (details) { - _runAnimation(details.velocity.pixelsPerSecond, size); - }, - child: Align( - alignment: _dragAlignment, - child: Card( - child: widget.child, - ), - ), - ); - } -} -'''; - -// From https://gist.github.com/johnpryan/289ecf8480ad005f01faeace70bd529a -const sampleCodeFlutterImplicitAnimations = ''' -import 'dart:math'; -import 'package:flutter/material.dart'; - -class DiscData { - static final _rng = Random(); - - final double size; - final Color color; - final Alignment alignment; - - DiscData() - : size = _rng.nextDouble() * 40 + 10, - color = Color.fromARGB( - _rng.nextInt(200), - _rng.nextInt(255), - _rng.nextInt(255), - _rng.nextInt(255), - ), - alignment = Alignment( - _rng.nextDouble() * 2 - 1, - _rng.nextDouble() * 2 - 1, - ); -} - -void main() async { - runApp( - MaterialApp( - debugShowCheckedModeBanner: false, - home: Scaffold( - body: Container( - color: const Color(0xFF15202D), - child: const SizedBox.expand( - child: VariousDiscs(50), - ), - ), - ), - ), - ); -} - -class VariousDiscs extends StatefulWidget { - final int numberOfDiscs; - - const VariousDiscs(this.numberOfDiscs); - - @override - State createState() => _VariousDiscsState(); -} - -class _VariousDiscsState extends State { - final _discs = []; - - @override - void initState() { - super.initState(); - _makeDiscs(); - } - - void _makeDiscs() { - _discs.clear(); - for (int i = 0; i < widget.numberOfDiscs; i++) { - _discs.add(DiscData()); - } - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () => setState(() { - _makeDiscs(); - }), - child: Stack( - children: [ - const Center( - child: Text( - 'Click a disc!', - style: TextStyle(color: Colors.white, fontSize: 50), - ), - ), - for (final disc in _discs) - Positioned.fill( - child: AnimatedAlign( - duration: const Duration(milliseconds: 500), - curve: Curves.easeInOut, - alignment: disc.alignment, - child: AnimatedContainer( - duration: const Duration(milliseconds: 500), - decoration: BoxDecoration( - color: disc.color, - shape: BoxShape.circle, - ), - height: disc.size, - width: disc.size, - ), - ), - ), - ], - ), - ); - } -} -'''; - -const sampleCodeMultiFoo = """ -import 'bar.dart'; - -void main() { - print(bar()); -} -"""; - -const sampleCodeMultiBar = ''' -bar() { - return 4; -} -'''; - -const sampleCodeLibraryMultiFoo = """ -library foofoo; - -part 'bar.dart'; - -void main() { - print(bar()); -} -"""; - -const sampleCodePartMultiBar = ''' -part of foofoo; - -bar() { - return 4; -} -'''; - -const sampleCodeAsync = """ -import 'dart:html'; - -void main() async { - print("hello"); - querySelector('#foo')?.text = 'bar'; - var foo = await HttpRequest.getString('http://www.google.com'); - print(foo); -} -"""; - -const sampleCodeError = ''' -void main() { - print("hello") -} -'''; - -const sampleCodeErrors = ''' -void main() { - print1("hello"); - print2("hello"); - print3("hello"); -} -'''; - -const sampleDart2Error = ''' -class Foo { - final bool isAlwaysNull; - Foo(this.isAlwaysNull) {} -} - -void main(List argv) { - var x = new Foo(null); - var y = 1; - y = x; -} -'''; - -/// Code fragments for testing multi file compiling. -/// These fragments are taken from [sampleCodeFlutterImplicitAnimations] and -/// only separated and re-arranged to facilitate testing multi file tests. - -const sampleCode3PartFlutterImplicitAnimationsImports = r''' -import 'dart:math'; -import 'package:flutter/material.dart'; -'''; - -const sampleCode3PartFlutterImplicitAnimationsMain = r''' - -void main() async { - runApp( - MaterialApp( - debugShowCheckedModeBanner: false, - home: Scaffold( - body: Container( - color: const Color(0xFF15202D), - child: const SizedBox.expand( - child: VariousDiscs(50), - ), - ), - ), - ), - ); -} -'''; - -const sampleCode3PartFlutterImplicitAnimationsDiscData = r''' - -class DiscData { - static final _rng = Random(); - - final double size; - final Color color; - final Alignment alignment; - - DiscData() - : size = _rng.nextDouble() * 40 + 10, - color = Color.fromARGB( - _rng.nextInt(200), - _rng.nextInt(255), - _rng.nextInt(255), - _rng.nextInt(255), - ), - alignment = Alignment( - _rng.nextDouble() * 2 - 1, - _rng.nextDouble() * 2 - 1, - ); -} -'''; - -const sampleCode3PartFlutterImplicitAnimationsVarious = r''' - -class VariousDiscs extends StatefulWidget { - final int numberOfDiscs; - - const VariousDiscs(this.numberOfDiscs); - - @override - State createState() => _VariousDiscsState(); -} - -class _VariousDiscsState extends State { - final _discs = []; - - @override - void initState() { - super.initState(); - _makeDiscs(); - } - - void _makeDiscs() { - _discs.clear(); - for (int i = 0; i < widget.numberOfDiscs; i++) { - _discs.add(DiscData()); - } - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () => setState(() { - _makeDiscs(); - }), - child: Stack( - children: [ - const Center( - child: Text( - 'Click a disc!', - style: TextStyle(color: Colors.white, fontSize: 50), - ), - ), - for (final disc in _discs) - Positioned.fill( - child: AnimatedAlign( - duration: const Duration(milliseconds: 500), - curve: Curves.easeInOut, - alignment: disc.alignment, - child: AnimatedContainer( - duration: const Duration(milliseconds: 500), - decoration: BoxDecoration( - color: disc.color, - shape: BoxShape.circle, - ), - height: disc.size, - width: disc.size, - ), - ), - ), - ], - ), - ); - } -} -'''; - -/// Create 2 files for multi file testing using imports. -const sampleCode2PartImportMain = ''' -$sampleCode3PartFlutterImplicitAnimationsImports -import 'various.dart'; -$sampleCode3PartFlutterImplicitAnimationsMain -'''; - -const sampleCode2PartImportVarious = ''' -$sampleCode3PartFlutterImplicitAnimationsImports -$sampleCode3PartFlutterImplicitAnimationsDiscData -$sampleCode3PartFlutterImplicitAnimationsVarious -'''; - -/// Create 3 separate files for multi file testing using imports. -/// Here main.dart will be importing 'various.dart' and 'discdata.dart', -/// and 'various.dart' importing 'discdata.dart'. -const sampleCode3PartImportMain = ''' -$sampleCode3PartFlutterImplicitAnimationsImports -import 'various.dart'; -import 'discdata.dart'; -$sampleCode3PartFlutterImplicitAnimationsMain -'''; - -const sampleCode3PartImportDiscData = ''' -$sampleCode3PartFlutterImplicitAnimationsImports -$sampleCode3PartFlutterImplicitAnimationsDiscData -'''; - -const sampleCode3PartImportVarious = ''' -$sampleCode3PartFlutterImplicitAnimationsImports -import 'discdata.dart'; -$sampleCode3PartFlutterImplicitAnimationsVarious -'''; - -/// Create 2 file test using "part 'various.dart'" to bring in second file. -const sampleCode2PartLibraryMain = ''' -library testanim; -$sampleCode3PartFlutterImplicitAnimationsImports -part 'various.dart'; -$sampleCode3PartFlutterImplicitAnimationsMain -'''; - -const sampleCode2PartVariousAndDiscDataPartOfTestAnim = ''' -part of testanim; -$sampleCode3PartFlutterImplicitAnimationsDiscData -$sampleCode3PartFlutterImplicitAnimationsVarious -'''; - -/// Create 3 file test using "part 'various.dart'" and "part 'discdata.dart'" -/// to bring in second and third files. -const sampleCode3PartLibraryMain = ''' -library testanim; -$sampleCode3PartFlutterImplicitAnimationsImports -part 'discdata.dart'; -part 'various.dart'; -$sampleCode3PartFlutterImplicitAnimationsMain -'''; - -const sampleCode3PartDiscDataPartOfTestAnim = ''' -part of testanim; -$sampleCode3PartFlutterImplicitAnimationsDiscData -'''; - -const sampleCode3PartVariousPartOfTestAnim = ''' -part of testanim; -$sampleCode3PartFlutterImplicitAnimationsVarious -'''; - -class _SourcesGroupFile { - String filename; - String content; - - _SourcesGroupFile(this.filename, this.content); -} - -/// This RegExp matches a variety of possible `main` function definition formats -/// Like: -/// - `Future main(List args) async {` -/// - `void main(List args) async {` -/// - `void main() {` -/// - `void main( List < String > args ) async {` -/// - `void main(Args arg) {` -/// - `main() {` -/// - `void main() {}` -/// - `void main() => runApp(MyApp());` -final RegExp mainFunctionDefinition = RegExp( - r'''[\s]*(Future)?[\<]?(void)?[\>]?[\s]*main[\s]*\((\s*\w*\s*\?\s*\w*\s*)?\)\s*(async)?\s*[\{|\=]+'''); - -/// Used to remove 2 or more '..' and any number of following slashes of '/' or '\'. -final RegExp sanitizeUpDirectories = RegExp(r'[\.]{2,}[\\\/]*'); - -/// Used to remove 'package:', 'dart:', 'http://', 'https://' etc. -final RegExp sanitizePackageDartHttp = RegExp(r'[\w]*[\:][\/]*'); - -/// Sanitizes [filename] by using the regular expressions -/// [sanitizeUpDirectories] and [sanitizePackageDartHttp] to remove -/// anything like 'package:', 'dart:' or 'http://', and then removing -/// runs of more than a single '.' (do not allow '..' up directories to -/// escape temp directory). -String _sanitizeFileName(String filename) { - filename = filename.replaceAll(sanitizePackageDartHttp, ''); - filename = filename.replaceAll(sanitizeUpDirectories, ''); - return filename; -} - -/// Goes through [sources] map of source files and sanitizes the filenames -/// and ensures that the file containing the main entry point that bootstrap -/// will be calling is called [kMainDart]. -/// [sources] is a map containing the source files in the format -/// `{ "filename1":"sourcecode1" .. "filenameN":"sourcecodeN"}`. -/// [activeSourceName] is the name of the source file active in the editor. -/// Returns [activeSourceName] or a new name if sanitized or renamed. -String sanitizeAndCheckFilenames(Map sources, - [String activeSourceName = kMainDart]) { - activeSourceName = _sanitizeFileName(activeSourceName); - - final files = - sources.entries.map((e) => _SourcesGroupFile(e.key, e.value)).toList(); - - var foundKMain = false; - // Check for kMainDart file and also sanitize filenames. - for (final sourceFile in files) { - sourceFile.filename = _sanitizeFileName(sourceFile.filename); - if (sourceFile.filename == kMainDart) { - foundKMain = true; - } - } - // One of the files must be named kMainDart. This is the file that the - // bootstrap dart file will import and call main() on. - if (!foundKMain && files.isNotEmpty) { - // We need to rename the file containing the main() function to kMainDart. - for (final sourceFile in files) { - if (mainFunctionDefinition.hasMatch(sourceFile.content)) { - // This file has a main() function, rename it to kMainDart - // and also change activeSourceName if that is the file being - // renamed. - if (sourceFile.filename == activeSourceName) { - activeSourceName = kMainDart; - } - sourceFile.filename = kMainDart; - foundKMain = true; - break; - } - } - if (!foundKMain) { - // No kMainDart was found so just change the first file to be kMainDart. - if (files[0].filename == activeSourceName) { - activeSourceName = kMainDart; - } - files[0].filename = kMainDart; - } - } - - // Take our files list and create a new files {filename:content} map. - sources.clear(); - for (final sourceFiles in files) { - sources[sourceFiles.filename] = sourceFiles.content; - } - - return activeSourceName; -} - -/// Count the total lines across all files in [sources] file map. -int countLines(Map sources) { - var totalLines = 0; - for (final filename in sources.keys) { - totalLines += countLinesInString(sources[filename]!); - } - return totalLines; -} - -// Character constants. -const int $lf = 10; -const int $cr = 13; - -/// Count lines in string (CR, LF or CR-LF can be line separators). -/// (Gives correct result as opposed to .split('\n').length, which -/// reports 1 extra line in many cases, and this does so without the -/// extra work .split() would do by creating the list of copied strings). -int countLinesInString(String str) { - final data = str.codeUnits; - var lines = 0; - final end = data.length; - var sliceStart = 0; - var char = 0; - for (var i = 0; i < end; i++) { - final previousChar = char; - char = data[i]; - if (char != $cr) { - if (char != $lf) continue; - if (previousChar == $cr) { - sliceStart = i + 1; - continue; - } - } - lines++; - sliceStart = i + 1; - } - if (sliceStart < end) { - lines++; - } - return lines; -} diff --git a/pkgs/dart_services/lib/src/common_server.dart b/pkgs/dart_services/lib/src/common_server.dart new file mode 100644 index 000000000..d721d7fbf --- /dev/null +++ b/pkgs/dart_services/lib/src/common_server.dart @@ -0,0 +1,326 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// 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'; +import 'dart:convert'; + +import 'package:logging/logging.dart'; +import 'package:shelf/shelf.dart'; +import 'package:shelf_router/shelf_router.dart'; + +import 'analysis.dart'; +import 'caching.dart'; +import 'compiling.dart'; +import 'project_templates.dart'; +import 'pub.dart'; +import 'sdk.dart'; +import 'shared/model.dart' as api; +import 'shelf_cors.dart' as shelf_cors; +import 'utils.dart'; + +part 'common_server.g.dart'; + +const jsonContentType = 'application/json; charset=utf-8'; + +const apiPrefix = '/api/'; + +const api3 = 'v3'; + +final Logger log = Logger('common_server'); + +class CommonServerImpl { + final Sdk sdk; + final ServerCache cache; + final String storageBucket; + + late Compiler compiler; + late AnalyzerWrapper analysisServer; + + CommonServerImpl( + this.sdk, + this.cache, { + this.storageBucket = 'nnbd_artifacts', + }); + + Future init() async { + log.fine('initing CommonServerImpl'); + + compiler = Compiler(sdk, storageBucket: storageBucket); + + analysisServer = AnalyzerWrapper(sdk.dartSdkPath); + await analysisServer.init(); + } + + Future shutdown() async { + log.fine('shutting down CommonServerImpl'); + + await cache.shutdown(); + + await analysisServer.shutdown(); + await compiler.dispose(); + } +} + +class CommonServerApi { + final CommonServerImpl impl; + final TaskScheduler scheduler = TaskScheduler(); + + /// The (lazily-constructed) router. + late final Router router = _$CommonServerApiRouter(this); + + CommonServerApi(this.impl); + + Future init() => impl.init(); + + Future shutdown() => impl.shutdown(); + + @Route.post('$apiPrefix/analyze') + Future analyze(Request request, String apiVersion) async { + if (apiVersion != api3) return unhandledVersion(apiVersion); + + final sourceRequest = + api.SourceRequest.fromJson(await request.readAsJson()); + + final result = await serialize(() { + return impl.analysisServer.analyze(sourceRequest.source); + }); + + return ok(result.toJson()); + } + + @Route.post('$apiPrefix/compile') + Future compile(Request request, String apiVersion) async { + if (apiVersion != api3) return unhandledVersion(apiVersion); + + final sourceRequest = + api.SourceRequest.fromJson(await request.readAsJson()); + + final results = await serialize(() { + return impl.compiler.compile(sourceRequest.source); + }); + + if (results.hasOutput) { + return ok(api.CompileResponse(result: results.compiledJS!).toJson()); + } else { + return failure(results.problems.map((p) => p.message).join('\n')); + } + } + + @Route.post('$apiPrefix/compileDDC') + Future compileDDC(Request request, String apiVersion) async { + if (apiVersion != api3) return unhandledVersion(apiVersion); + + final sourceRequest = + api.SourceRequest.fromJson(await request.readAsJson()); + + final results = await serialize(() { + return impl.compiler.compileDDC(sourceRequest.source); + }); + + if (results.hasOutput) { + var modulesBaseUrl = results.modulesBaseUrl; + if (modulesBaseUrl != null && modulesBaseUrl.isEmpty) { + modulesBaseUrl = null; + } + return ok(api.CompileDDCResponse( + result: results.compiledJS!, + modulesBaseUrl: modulesBaseUrl, + ).toJson()); + } else { + return failure(results.problems.map((p) => p.message).join('\n')); + } + } + + @Route.post('$apiPrefix/complete') + Future complete(Request request, String apiVersion) async { + if (apiVersion != api3) return unhandledVersion(apiVersion); + + final sourceRequest = + api.SourceRequest.fromJson(await request.readAsJson()); + + final result = await serialize(() => impl.analysisServer + .completeV3(sourceRequest.source, sourceRequest.offset!)); + + return ok(result.toJson()); + } + + @Route.post('$apiPrefix/fixes') + Future fixes(Request request, String apiVersion) async { + if (apiVersion != api3) return unhandledVersion(apiVersion); + + final sourceRequest = + api.SourceRequest.fromJson(await request.readAsJson()); + + final result = await serialize(() => impl.analysisServer + .fixesV3(sourceRequest.source, sourceRequest.offset!)); + + return ok(result.toJson()); + } + + @Route.post('$apiPrefix/format') + Future format(Request request, String apiVersion) async { + if (apiVersion != api3) return unhandledVersion(apiVersion); + + final sourceRequest = + api.SourceRequest.fromJson(await request.readAsJson()); + + final result = await serialize(() { + return impl.analysisServer.format( + sourceRequest.source, + sourceRequest.offset, + ); + }); + + return ok(result.toJson()); + } + + @Route.post('$apiPrefix/document') + Future document(Request request, String apiVersion) async { + if (apiVersion != api3) return unhandledVersion(apiVersion); + + final sourceRequest = + api.SourceRequest.fromJson(await request.readAsJson()); + + final result = await serialize(() { + return impl.analysisServer.dartdocV3( + sourceRequest.source, + sourceRequest.offset!, + ); + }); + + return ok(result.toJson()); + } + + @Route.get('$apiPrefix/version') + Future versionGet(Request request, String apiVersion) async { + if (apiVersion != api3) return unhandledVersion(apiVersion); + + return ok(version().toJson()); + } + + Response ok(Map json) { + return Response.ok( + _jsonEncoder.convert(json), + encoding: utf8, + headers: _jsonHeaders, + ); + } + + Response failure(String message) { + return Response.badRequest(body: message); + } + + Response unhandledVersion(String apiVersion) { + return Response.notFound('unhandled api version: $apiVersion'); + } + + Future serialize(Future Function() fn) { + return scheduler.schedule(ClosureTask( + fn, + timeoutDuration: const Duration(minutes: 5), + )); + } + + api.VersionResponse version() { + final sdk = impl.sdk; + + final packageVersions = getPackageVersions(); + + final packages = [ + for (final packageName in packageVersions.keys) + api.PackageInfo( + name: packageName, + version: packageVersions[packageName]!, + supported: isSupportedPackage(packageName), + ), + ]; + + return api.VersionResponse( + dartVersion: sdk.dartVersion, + flutterVersion: sdk.flutterVersion, + engineVersion: sdk.engineVersion, + experiments: sdk.experiments, + packages: packages, + ); + } +} + +class BadRequest implements Exception { + final String message; + + BadRequest(this.message); + + @override + String toString() => message; +} + +final JsonEncoder _jsonEncoder = const JsonEncoder.withIndent(' '); + +const Map _jsonHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Content-Type': jsonContentType, +}; + +extension RequestExtension on Request { + Future> readAsJson() async { + final body = await readAsString(); + return body.isNotEmpty + ? (json.decode(body) as Map) + : {}; + } +} + +Middleware createCustomCorsHeadersMiddleware() { + return shelf_cors.createCorsHeadersMiddleware(corsHeaders: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', + 'Access-Control-Allow-Headers': + 'Origin, X-Requested-With, Content-Type, Accept, x-goog-api-client' + }); +} + +Middleware logRequestsToLogger(Logger log) { + return (Handler innerHandler) { + return (request) { + final watch = Stopwatch()..start(); + + return Future.sync(() => innerHandler(request)).then((response) { + log.info(_formatMessage(request, watch.elapsed, response: response)); + + return response; + }, onError: (Object error, StackTrace stackTrace) { + if (error is HijackException) throw error; + + log.info(_formatMessage(request, watch.elapsed, error: error)); + + // ignore: only_throw_errors + throw error; + }); + }; + }; +} + +String _formatMessage( + Request request, + Duration elapsedTime, { + Response? response, + Object? error, +}) { + final method = request.method; + final requestedUri = request.requestedUri; + final statusCode = response?.statusCode; + final bytes = response?.contentLength; + final size = ((bytes ?? 0) + 1023) ~/ 1024; + + final ms = elapsedTime.inMilliseconds; + final query = requestedUri.query == '' ? '' : '?${requestedUri.query}'; + + var message = '${ms.toString().padLeft(5)}ms ${size.toString().padLeft(4)}k ' + '$statusCode $method ${requestedUri.path}$query'; + if (error != null) { + message = '$message [$error]'; + } + + return message; +} diff --git a/pkgs/dart_services/lib/src/common_server.g.dart b/pkgs/dart_services/lib/src/common_server.g.dart new file mode 100644 index 000000000..f548d8b29 --- /dev/null +++ b/pkgs/dart_services/lib/src/common_server.g.dart @@ -0,0 +1,52 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'common_server.dart'; + +// ************************************************************************** +// ShelfRouterGenerator +// ************************************************************************** + +Router _$CommonServerApiRouter(CommonServerApi service) { + final router = Router(); + router.add( + 'POST', + r'/api//analyze', + service.analyze, + ); + router.add( + 'POST', + r'/api//compile', + service.compile, + ); + router.add( + 'POST', + r'/api//compileDDC', + service.compileDDC, + ); + router.add( + 'POST', + r'/api//complete', + service.complete, + ); + router.add( + 'POST', + r'/api//fixes', + service.fixes, + ); + router.add( + 'POST', + r'/api//format', + service.format, + ); + router.add( + 'POST', + r'/api//document', + service.document, + ); + router.add( + 'GET', + r'/api//version', + service.versionGet, + ); + return router; +} diff --git a/pkgs/dart_services/lib/src/common_server_api.dart b/pkgs/dart_services/lib/src/common_server_api.dart deleted file mode 100644 index 74121111a..000000000 --- a/pkgs/dart_services/lib/src/common_server_api.dart +++ /dev/null @@ -1,624 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// 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'; -import 'dart:convert'; - -import 'package:logging/logging.dart'; -import 'package:meta/meta.dart'; -import 'package:protobuf/protobuf.dart'; -import 'package:shelf/shelf.dart'; -import 'package:shelf_router/shelf_router.dart'; - -import 'common_server_impl.dart' show BadRequest, CommonServerImpl; -import 'project.dart'; -import 'protos/dart_services.pb.dart' as proto; -import 'pub.dart'; -import 'scheduler.dart'; -import 'shared/model.dart' as api; -import 'shared/services.dart'; -import 'shelf_cors.dart' as shelf_cors; - -export 'common_server_impl.dart' show log; - -part 'common_server_api.g.dart'; - -const protobufContentType = 'application/x-protobuf'; -const jsonContentType = 'application/json; charset=utf-8'; - -const oldApiPrefix = '/api/dartservices/'; -const newApiPrefix = '/api/'; - -const api2 = 'v2'; -const api3 = 'v3'; - -class CommonServerApi { - final CommonServerImpl _impl; - final TaskScheduler scheduler = TaskScheduler(); - - CommonServerApi(this._impl); - - @Route.post('$oldApiPrefix/analyze') - @Route.post('$newApiPrefix/analyze') - Future analyze(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceRequest.fromBuffer, - transform: _impl.analyze, - ); - } else if (apiVersion == api3) { - final sourceRequest = - api.SourceRequest.fromJson(await request.readAsJson()); - - final result = await serialize(() { - return _impl.analysisServer.analyze(sourceRequest.source); - }); - - return ok(api.AnalysisResponse( - issues: result.issues.map((issue) { - return api.AnalysisIssue( - kind: issue.kind, - message: issue.message, - location: api.Location( - charStart: issue.charStart, - charLength: issue.charLength, - line: issue.line, - column: issue.column, - ), - correction: issue.hasCorrection() ? issue.correction : null, - url: issue.hasUrl() ? issue.url : null, - contextMessages: issue.diagnosticMessages.map((diagnostic) { - return api.DiagnosticMessage( - message: diagnostic.message, - location: Location( - charStart: diagnostic.charStart, - charLength: diagnostic.charLength, - line: diagnostic.line, - column: diagnostic.column, - ), - ); - }).toList(), - ); - }).toList(), - packageImports: result.packageImports, - ).toJson()); - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.post('$oldApiPrefix/compile') - @Route.post('$newApiPrefix/compile') - Future compile(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.CompileRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.CompileRequest.fromBuffer, - transform: _impl.compile, - ); - } else if (apiVersion == api3) { - final sourceRequest = - api.SourceRequest.fromJson(await request.readAsJson()); - final results = await serialize(() { - return _impl.compiler.compile(sourceRequest.source); - }); - if (results.hasOutput) { - return ok(api.CompileResponse(result: results.compiledJS!).toJson()); - } else { - return failure(results.problems.map((p) => p.message).join('\n')); - } - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.post('$oldApiPrefix/compileDDC') - @Route.post('$newApiPrefix/compileDDC') - Future compileDDC(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.CompileDDCRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.CompileDDCRequest.fromBuffer, - transform: _impl.compileDDC, - ); - } else if (apiVersion == api3) { - final sourceRequest = - api.SourceRequest.fromJson(await request.readAsJson()); - final results = await serialize(() { - return _impl.compiler.compileDDC(sourceRequest.source); - }); - if (results.hasOutput) { - var modulesBaseUrl = results.modulesBaseUrl; - if (modulesBaseUrl != null && modulesBaseUrl.isEmpty) { - modulesBaseUrl = null; - } - return ok(api.CompileDDCResponse( - result: results.compiledJS!, - modulesBaseUrl: modulesBaseUrl, - ).toJson()); - } else { - return failure(results.problems.map((p) => p.message).join('\n')); - } - } else { - return unhandledVersion(apiVersion); - } - } - - @experimental - @Route.post('$oldApiPrefix/_flutterBuild') - @Route.post('$newApiPrefix/_flutterBuild') - Future flutterBuild(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceRequest.fromBuffer, - transform: _impl.flutterBuild, - ); - } else if (apiVersion == api3) { - final sourceRequest = - api.SourceRequest.fromJson(await request.readAsJson()); - final results = await serialize(() { - return _impl.compiler.flutterBuild(sourceRequest.source); - }); - - if (results.hasOutput) { - return ok(api.FlutterBuildResponse( - artifacts: { - 'main.dart.js': results.compiledJavaScript!, - }, - ).toJson()); - } else { - return failure(results.compilationIssues ?? ''); - } - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.post('$oldApiPrefix/complete') - @Route.post('$newApiPrefix/complete') - Future complete(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceRequest.fromBuffer, - transform: _impl.complete, - ); - } else if (apiVersion == api3) { - final sourceRequest = - api.SourceRequest.fromJson(await request.readAsJson()); - final result = await serialize(() => _impl.analysisServer - .completeV3(sourceRequest.source, sourceRequest.offset!)); - return ok(result.toJson()); - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.post('$oldApiPrefix/fixes') - @Route.post('$newApiPrefix/fixes') - Future fixes(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceRequest.fromBuffer, - transform: _impl.fixes, - ); - } else if (apiVersion == api3) { - final sourceRequest = - api.SourceRequest.fromJson(await request.readAsJson()); - final result = await serialize(() => _impl.analysisServer - .fixesV3(sourceRequest.source, sourceRequest.offset!)); - return ok(result.toJson()); - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.post('$oldApiPrefix/assists') - @Route.post('$newApiPrefix/assists') - Future assists(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceRequest.fromBuffer, - transform: _impl.assists, - ); - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.post('$oldApiPrefix/format') - @Route.post('$newApiPrefix/format') - Future format(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceRequest.fromBuffer, - transform: _impl.format, - ); - } else if (apiVersion == api3) { - final sourceRequest = - api.SourceRequest.fromJson(await request.readAsJson()); - - final result = await serialize(() { - return _impl.analysisServer.format( - sourceRequest.source, - sourceRequest.offset, - ); - }); - return ok(api.FormatResponse( - source: result.newString, - offset: result.offset, - ).toJson()); - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.post('$oldApiPrefix/document') - @Route.post('$newApiPrefix/document') - Future document(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceRequest.fromBuffer, - transform: _impl.document, - ); - } else if (apiVersion == api3) { - final sourceRequest = - api.SourceRequest.fromJson(await request.readAsJson()); - - final result = await serialize(() { - return _impl.analysisServer.dartdocV3( - sourceRequest.source, - sourceRequest.offset!, - ); - }); - return ok(result.toJson()); - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.post('$oldApiPrefix/version') - @Route.post('$newApiPrefix/version') - Future versionPost(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.VersionRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.VersionRequest.fromBuffer, - transform: _impl.version, - ); - } else { - return unhandledVersion(apiVersion); - } - } - - @Route.get('$oldApiPrefix/version') - @Route.get('$newApiPrefix/version') - Future versionGet(Request request, String apiVersion) async { - if (apiVersion == api2) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.VersionRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.VersionRequest.fromBuffer, - transform: _impl.version, - ); - } else if (apiVersion == api3) { - return ok(version().toJson()); - } else { - return unhandledVersion(apiVersion); - } - } - - // Beginning of multi file map end points: - @Route.post('$oldApiPrefix/analyzeFiles') - @Route.post('$newApiPrefix/analyzeFiles') - Future analyzeFiles(Request request, String apiVersion) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceFilesRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceFilesRequest.fromBuffer, - transform: _impl.analyzeFiles, - ); - } - - @Route.post('$oldApiPrefix/compileFiles') - @Route.post('$newApiPrefix/compileFiles') - Future compileFiles(Request request, String apiVersion) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.CompileFilesRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.CompileFilesRequest.fromBuffer, - transform: _impl.compileFiles, - ); - } - - @Route.post('$oldApiPrefix/compileFilesDDC') - @Route.post('$newApiPrefix/compileFilesDDC') - Future compileFilesDDC(Request request, String apiVersion) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.CompileFilesDDCRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.CompileFilesDDCRequest.fromBuffer, - transform: _impl.compileFilesDDC, - ); - } - - @Route.post('$oldApiPrefix/completeFiles') - @Route.post('$newApiPrefix/completeFiles') - Future completeFiles(Request request, String apiVersion) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceFilesRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceFilesRequest.fromBuffer, - transform: _impl.completeFiles, - ); - } - - @Route.post('$oldApiPrefix/fixesFiles') - @Route.post('$newApiPrefix/fixesFiles') - Future fixesFiles(Request request, String apiVersion) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceFilesRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceFilesRequest.fromBuffer, - transform: _impl.fixesFiles, - ); - } - - @Route.post('$oldApiPrefix/assistsFiles') - @Route.post('$newApiPrefix/assistsFiles') - Future assistsFiles(Request request, String apiVersion) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceFilesRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceFilesRequest.fromBuffer, - transform: _impl.assistsFiles, - ); - } - - @Route.post('$oldApiPrefix/documentFiles') - @Route.post('$newApiPrefix/documentFiles') - Future documentFiles(Request request, String apiVersion) { - return _processRequest( - request, - decodeFromJSON: (json) => - proto.SourceFilesRequest.create()..mergeFromProto3Json(json), - decodeFromProto: proto.SourceFilesRequest.fromBuffer, - transform: _impl.documentFiles, - ); - } - - // *** // - - Response ok(Map json) { - return Response.ok(_jsonEncoder.convert(json), - encoding: utf8, headers: _jsonHeaders); - } - - Response failure(String message) { - return Response.badRequest(body: message); - } - - Response unhandledVersion(String apiVersion) { - return Response.notFound('unhandled api version: $apiVersion'); - } - - Future serialize(Future Function() fn) { - return scheduler.schedule(ClosureTask( - fn, - timeoutDuration: const Duration(minutes: 5), - )); - } - - api.VersionResponse version() { - final sdk = _impl.sdk; - - final packageVersions = getPackageVersions(); - final packages = [ - for (final packageName in packageVersions.keys) - api.PackageInfo( - name: packageName, - version: packageVersions[packageName]!, - supported: isSupportedPackage(packageName), - ), - ]; - - return api.VersionResponse( - dartVersion: sdk.dartVersion, - flutterVersion: sdk.flutterVersion, - engineVersion: sdk.engineVersion, - experiments: sdk.experiments, - packages: packages, - ); - } - - /// The (lazily-constructed) router. - late final Router router = _$CommonServerApiRouter(this); - - // We are serving requests that are arriving in both Protobuf binary encoding, - // and Protobuf JSON encoding. To handle this we need the ability to decode - // the requests and encode the responses. We also need to know how to do the - // work the request is requesting. - - Future _processRequest( - Request request, { - required I Function(List bytes) decodeFromProto, - required I Function(Object json) decodeFromJSON, - required Future Function(I input) transform, - }) async { - return scheduler.schedule(_ServerTask( - request, - decodeFromProto: decodeFromProto, - decodeFromJSON: decodeFromJSON, - transform: transform, - )); - } -} - -final JsonEncoder _jsonEncoder = const JsonEncoder.withIndent(' '); - -const _jsonHeaders = { - 'Access-Control-Allow-Origin': '*', - 'Content-Type': jsonContentType, -}; - -const _protobufHeaders = { - 'Access-Control-Allow-Origin': '*', - 'Content-Type': protobufContentType, -}; - -class _ServerTask extends Task { - final Request request; - final I Function(List bytes) decodeFromProto; - final I Function(Object json) decodeFromJSON; - final Future Function(I input) transform; - - _ServerTask( - this.request, { - required this.decodeFromProto, - required this.decodeFromJSON, - required this.transform, - }); - - @override - Duration get timeoutDuration => const Duration(minutes: 5); - - @override - Future perform() async { - if (request.mimeType == protobufContentType) { - // Dealing with binary Protobufs - final body = []; - await for (final chunk in request.read()) { - body.addAll(chunk); - } - try { - final response = await transform(decodeFromProto(body)); - return Response.ok( - response.writeToBuffer(), - headers: _protobufHeaders, - ); - } on BadRequest catch (e) { - return Response(400, - headers: _protobufHeaders, - body: (proto.BadRequest.create() - ..error = (proto.ErrorMessage.create()..message = e.cause)) - .writeToBuffer()); - } - } else { - // Dealing with JSON encoded Protobufs - final body = await request.readAsString(); - try { - final response = await transform( - decodeFromJSON(body.isNotEmpty ? json.decode(body) as Object : {})); - return Response.ok( - _jsonEncoder.convert(response.toProto3Json()), - encoding: utf8, - headers: _jsonHeaders, - ); - } on BadRequest catch (e) { - return Response(400, - headers: _jsonHeaders, - encoding: utf8, - body: _jsonEncoder.convert((proto.BadRequest.create() - ..error = (proto.ErrorMessage.create()..message = e.cause)) - .toProto3Json())); - } - } - } -} - -extension RequestExtension on Request { - Future> readAsJson() async { - final body = await readAsString(); - return body.isNotEmpty - ? (json.decode(body) as Map) - : {}; - } -} - -Middleware createCustomCorsHeadersMiddleware() { - return shelf_cors.createCorsHeadersMiddleware(corsHeaders: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', - 'Access-Control-Allow-Headers': - 'Origin, X-Requested-With, Content-Type, Accept, x-goog-api-client' - }); -} - -Middleware logRequestsToLogger(Logger log) { - return (Handler innerHandler) { - return (request) { - final watch = Stopwatch()..start(); - - return Future.sync(() => innerHandler(request)).then((response) { - log.info(_formatMessage(request, watch.elapsed, response: response)); - - return response; - }, onError: (Object error, StackTrace stackTrace) { - if (error is HijackException) throw error; - - log.info(_formatMessage(request, watch.elapsed, error: error)); - - // ignore: only_throw_errors - throw error; - }); - }; - }; -} - -String _formatMessage( - Request request, - Duration elapsedTime, { - Response? response, - Object? error, -}) { - final method = request.method; - final requestedUri = request.requestedUri; - final statusCode = response?.statusCode; - final bytes = response?.contentLength; - final size = ((bytes ?? 0) + 1023) ~/ 1024; - - final ms = elapsedTime.inMilliseconds; - final query = requestedUri.query == '' ? '' : '?${requestedUri.query}'; - - var message = '${ms.toString().padLeft(5)}ms ${size.toString().padLeft(4)}k ' - '$statusCode $method ${requestedUri.path}$query'; - if (error != null) { - message = '$message [$error]'; - } - - return message; -} diff --git a/pkgs/dart_services/lib/src/common_server_api.g.dart b/pkgs/dart_services/lib/src/common_server_api.g.dart deleted file mode 100644 index 89de3665a..000000000 --- a/pkgs/dart_services/lib/src/common_server_api.g.dart +++ /dev/null @@ -1,192 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'common_server_api.dart'; - -// ************************************************************************** -// ShelfRouterGenerator -// ************************************************************************** - -Router _$CommonServerApiRouter(CommonServerApi service) { - final router = Router(); - router.add( - 'POST', - r'/api/dartservices//analyze', - service.analyze, - ); - router.add( - 'POST', - r'/api//analyze', - service.analyze, - ); - router.add( - 'POST', - r'/api/dartservices//compile', - service.compile, - ); - router.add( - 'POST', - r'/api//compile', - service.compile, - ); - router.add( - 'POST', - r'/api/dartservices//compileDDC', - service.compileDDC, - ); - router.add( - 'POST', - r'/api//compileDDC', - service.compileDDC, - ); - router.add( - 'POST', - r'/api/dartservices//_flutterBuild', - service.flutterBuild, - ); - router.add( - 'POST', - r'/api//_flutterBuild', - service.flutterBuild, - ); - router.add( - 'POST', - r'/api/dartservices//complete', - service.complete, - ); - router.add( - 'POST', - r'/api//complete', - service.complete, - ); - router.add( - 'POST', - r'/api/dartservices//fixes', - service.fixes, - ); - router.add( - 'POST', - r'/api//fixes', - service.fixes, - ); - router.add( - 'POST', - r'/api/dartservices//assists', - service.assists, - ); - router.add( - 'POST', - r'/api//assists', - service.assists, - ); - router.add( - 'POST', - r'/api/dartservices//format', - service.format, - ); - router.add( - 'POST', - r'/api//format', - service.format, - ); - router.add( - 'POST', - r'/api/dartservices//document', - service.document, - ); - router.add( - 'POST', - r'/api//document', - service.document, - ); - router.add( - 'POST', - r'/api/dartservices//version', - service.versionPost, - ); - router.add( - 'POST', - r'/api//version', - service.versionPost, - ); - router.add( - 'GET', - r'/api/dartservices//version', - service.versionGet, - ); - router.add( - 'GET', - r'/api//version', - service.versionGet, - ); - router.add( - 'POST', - r'/api/dartservices//analyzeFiles', - service.analyzeFiles, - ); - router.add( - 'POST', - r'/api//analyzeFiles', - service.analyzeFiles, - ); - router.add( - 'POST', - r'/api/dartservices//compileFiles', - service.compileFiles, - ); - router.add( - 'POST', - r'/api//compileFiles', - service.compileFiles, - ); - router.add( - 'POST', - r'/api/dartservices//compileFilesDDC', - service.compileFilesDDC, - ); - router.add( - 'POST', - r'/api//compileFilesDDC', - service.compileFilesDDC, - ); - router.add( - 'POST', - r'/api/dartservices//completeFiles', - service.completeFiles, - ); - router.add( - 'POST', - r'/api//completeFiles', - service.completeFiles, - ); - router.add( - 'POST', - r'/api/dartservices//fixesFiles', - service.fixesFiles, - ); - router.add( - 'POST', - r'/api//fixesFiles', - service.fixesFiles, - ); - router.add( - 'POST', - r'/api/dartservices//assistsFiles', - service.assistsFiles, - ); - router.add( - 'POST', - r'/api//assistsFiles', - service.assistsFiles, - ); - router.add( - 'POST', - r'/api/dartservices//documentFiles', - service.documentFiles, - ); - router.add( - 'POST', - r'/api//documentFiles', - service.documentFiles, - ); - return router; -} diff --git a/pkgs/dart_services/lib/src/common_server_impl.dart b/pkgs/dart_services/lib/src/common_server_impl.dart deleted file mode 100644 index a7b763220..000000000 --- a/pkgs/dart_services/lib/src/common_server_impl.dart +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file -// 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'; -import 'dart:convert'; - -import 'package:convert/convert.dart'; -import 'package:crypto/crypto.dart'; -import 'package:logging/logging.dart'; - -import 'analyzer_wrapper.dart'; -import 'common.dart'; -import 'compiler.dart'; -import 'project.dart'; -import 'protos/dart_services.pb.dart' as proto; -import 'pub.dart'; -import 'sdk.dart'; -import 'server_cache.dart'; - -const Duration _standardExpiration = Duration(hours: 1); -final Logger log = Logger('common_server'); - -class BadRequest implements Exception { - final String cause; - - BadRequest(this.cause); -} - -class CommonServerImpl { - final ServerCache _cache; - final Sdk sdk; - final String storageBucket; - - late Compiler compiler; - late AnalyzerWrapper analysisServer; - - CommonServerImpl(this.sdk, this._cache, - {this.storageBucket = 'nnbd_artifacts'}); - - Future init() async { - log.fine('initing CommonServerImpl'); - - compiler = Compiler(sdk, storageBucket: storageBucket); - - analysisServer = AnalyzerWrapper(sdk.dartSdkPath); - await analysisServer.init(); - } - - Future shutdown() { - return Future.wait(>[ - analysisServer.shutdown(), - compiler.dispose(), - Future.sync(_cache.shutdown) - ]).timeout(const Duration(minutes: 1)); - } - - Future analyze(proto.SourceRequest request) { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - - return analysisServer.analyze(request.source); - } - - Future compile(proto.CompileRequest request) { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - - return _compileDart2js({kMainDart: request.source}, - returnSourceMap: request.returnSourceMap); - } - - Future compileDDC(proto.CompileDDCRequest request) { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - - return _compileDDC({kMainDart: request.source}); - } - - Future flutterBuild( - proto.SourceRequest request, - ) { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - - return _flutterBuild(source: request.source); - } - - Future complete(proto.SourceRequest request) { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - if (!request.hasOffset()) { - throw BadRequest('Missing parameter: \'offset\''); - } - - return analysisServer.complete(request.source, request.offset); - } - - Future fixes(proto.SourceRequest request) { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - if (!request.hasOffset()) { - throw BadRequest('Missing parameter: \'offset\''); - } - - return analysisServer.getFixes(request.source, request.offset); - } - - Future assists(proto.SourceRequest request) { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - if (!request.hasOffset()) { - throw BadRequest('Missing parameter: \'offset\''); - } - - return analysisServer.getAssists(request.source, request.offset); - } - - Future format(proto.SourceRequest request) { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - - return analysisServer.format(request.source, request.offset); - } - - Future document(proto.SourceRequest request) async { - if (!request.hasSource()) { - throw BadRequest('Missing parameter: \'source\''); - } - if (!request.hasOffset()) { - throw BadRequest('Missing parameter: \'offset\''); - } - - return proto.DocumentResponse() - ..info - .addAll(await analysisServer.dartdoc(request.source, request.offset)); - } - - // Beginning of multi files map entry points: - Future analyzeFiles(proto.SourceFilesRequest request) { - if (request.files.isEmpty) { - throw BadRequest('Missing parameter: \'files\''); - } - - return analysisServer.analyzeFiles(request.files, request.activeSourceName); - } - - Future compileFiles( - proto.CompileFilesRequest request) { - if (request.files.isEmpty) { - throw BadRequest('Missing parameter: \'files\''); - } - - return _compileDart2js(request.files, - returnSourceMap: request.returnSourceMap); - } - - Future compileFilesDDC( - proto.CompileFilesDDCRequest request) { - if (request.files.isEmpty) { - throw BadRequest('Missing parameter: \'files\''); - } - - return _compileDDC(request.files); - } - - Future completeFiles( - proto.SourceFilesRequest request) { - if (request.files.isEmpty) { - throw BadRequest('Missing parameter: \'files\''); - } - if (!request.hasActiveSourceName()) { - throw BadRequest('Missing parameter: \'activeSourceName\''); - } - if (!request.hasOffset()) { - throw BadRequest('Missing parameter: \'offset\''); - } - - return analysisServer.completeFiles( - request.files, request.activeSourceName, request.offset); - } - - Future fixesFiles(proto.SourceFilesRequest request) { - if (request.files.isEmpty) { - throw BadRequest('Missing parameter: \'files\''); - } - if (!request.hasActiveSourceName()) { - throw BadRequest('Missing parameter: \'activeSourceName\''); - } - if (!request.hasOffset()) { - throw BadRequest('Missing parameter: \'offset\''); - } - - return analysisServer.getFixesMulti( - request.files, request.activeSourceName, request.offset); - } - - Future assistsFiles(proto.SourceFilesRequest request) { - if (request.files.isEmpty) { - throw BadRequest('Missing parameter: \'files\''); - } - if (!request.hasActiveSourceName()) { - throw BadRequest('Missing parameter: \'activeSourceName\''); - } - if (!request.hasOffset()) { - throw BadRequest('Missing parameter: \'offset\''); - } - - return analysisServer.getAssistsMulti( - request.files, request.activeSourceName, request.offset); - } - - Future documentFiles( - proto.SourceFilesRequest request) async { - if (request.files.isEmpty) { - throw BadRequest('Missing parameter: \'files\''); - } - if (!request.hasActiveSourceName()) { - throw BadRequest('Missing parameter: \'activeSourceName\''); - } - if (!request.hasOffset()) { - throw BadRequest('Missing parameter: \'offset\''); - } - - return proto.DocumentResponse() - ..info.addAll(await analysisServer.dartdocMulti( - request.files, request.activeSourceName, request.offset)); - } - // End of files map entry points. - - Future version(proto.VersionRequest _) { - final packageVersions = getPackageVersions(); - final packageInfos = [ - for (final packageName in packageVersions.keys) - proto.PackageInfo() - ..name = packageName - ..version = packageVersions[packageName]! - ..supported = isSupportedPackage(packageName), - ]; - - return Future.value( - proto.VersionResponse() - ..sdkVersion = sdk.version - ..sdkVersionFull = sdk.dartVersion - ..flutterVersion = sdk.flutterVersion - ..flutterEngineSha = sdk.engineVersion - ..packageInfo.addAll(packageInfos) - ..experiment.addAll(sdk.experiments), - ); - } - - Future _compileDart2js( - Map sources, { - bool returnSourceMap = false, - }) async { - try { - final sourceHash = _hashSources(sources); - final memCacheKey = '%%COMPILE:v0' - ':returnSourceMap:$returnSourceMap:source:$sourceHash'; - - final result = await _checkCache(memCacheKey); - if (result != null) { - log.fine('CACHE: Cache hit for compileDart2js'); - final resultObj = json.decode(result) as Map; - final response = proto.CompileResponse() - ..result = resultObj['compiledJS'] as String; - if (resultObj['sourceMap'] != null) { - response.sourceMap = resultObj['sourceMap'] as String; - } - return response; - } - - log.fine('CACHE: MISS for compileDart2js'); - final watch = Stopwatch()..start(); - - final results = await compiler.compileFiles(sources, - returnSourceMap: returnSourceMap); - - if (results.hasOutput) { - final lineCount = countLines(sources); - final outputSize = (results.compiledJS?.length ?? 0 / 1024).ceil(); - final ms = watch.elapsedMilliseconds; - log.fine('PERF: Compiled $lineCount lines of Dart into ' - '${outputSize}kb of JavaScript in ${ms}ms using dart2js.'); - final sourceMap = returnSourceMap ? results.sourceMap : null; - - final cachedResult = const JsonEncoder().convert({ - 'compiledJS': results.compiledJS, - 'sourceMap': sourceMap, - }); - // Don't block on cache set. - unawaited(_setCache(memCacheKey, cachedResult)); - final compileResponse = proto.CompileResponse(); - compileResponse.result = results.compiledJS ?? ''; - if (sourceMap != null) { - compileResponse.sourceMap = sourceMap; - } - return compileResponse; - } else { - final problems = results.problems; - final errors = problems.map(_printCompileProblem).join('\n'); - throw BadRequest(errors); - } - } catch (e, st) { - if (e is! BadRequest) { - log.severe('Error during compile (dart2js) on "$sources"', e, st); - } - rethrow; - } - } - - Future _compileDDC( - Map sources) async { - try { - final sourceHash = _hashSources(sources); - final memCacheKey = '%%COMPILE_DDC:v0:source:$sourceHash'; - - final result = await _checkCache(memCacheKey); - if (result != null) { - log.fine('CACHE: Cache hit for compileDDC'); - final resultObj = json.decode(result) as Map; - return proto.CompileDDCResponse() - ..result = resultObj['compiledJS'] as String - ..modulesBaseUrl = resultObj['modulesBaseUrl'] as String; - } - - log.fine('CACHE: MISS for compileDDC'); - final watch = Stopwatch()..start(); - - final results = await compiler.compileFilesDDC(sources); - - if (results.hasOutput) { - final lineCount = countLines(sources); - final outputSize = (results.compiledJS?.length ?? 0 / 1024).ceil(); - final ms = watch.elapsedMilliseconds; - log.fine('PERF: Compiled $lineCount lines of Dart into ' - '${outputSize}kb of JavaScript in ${ms}ms using DDC.'); - - final cachedResult = const JsonEncoder().convert({ - 'compiledJS': results.compiledJS ?? '', - 'modulesBaseUrl': results.modulesBaseUrl ?? '', - }); - // Don't block on cache set. - unawaited(_setCache(memCacheKey, cachedResult)); - return proto.CompileDDCResponse() - ..result = results.compiledJS ?? '' - ..modulesBaseUrl = results.modulesBaseUrl ?? ''; - } else { - final problems = results.problems; - final errors = problems.map(_printCompileProblem).join('\n'); - throw BadRequest(errors); - } - } catch (e, st) { - if (e is! BadRequest) { - log.severe('Error during compile (DDC) on "$sources"', e, st); - } - rethrow; - } - } - - Future _flutterBuild({ - required String source, - }) async { - final results = await compiler.flutterBuild(source); - if (results.hasOutput) { - return proto.FlutterBuildResponse() - ..artifacts['main.dart.js'] = results.compiledJavaScript!; - } else { - throw BadRequest(results.compilationIssues!); - } - } - - Future _checkCache(String query) => _cache.get(query); - - Future _setCache(String query, String result) => - _cache.set(query, result, expiration: _standardExpiration); -} - -String _printCompileProblem(CompilationProblem problem) => problem.message; - -String _hashSources(Map sources) { - if (sources.length == 1) { - // Special case optimized for single source file (and to work as before). - return sha1.convert(sources.values.first.codeUnits).toString(); - } else { - // Use chunk hashing method for >1 source files. - final hashoutput = AccumulatorSink(); - final sha1Chunker = sha1.startChunkedConversion(hashoutput); - sources.forEach((_, filecontents) { - sha1Chunker.add(filecontents.codeUnits); - }); - sha1Chunker.close(); - return hashoutput.events.single.toString(); - } -} diff --git a/pkgs/dart_services/lib/src/compiler.dart b/pkgs/dart_services/lib/src/compiling.dart similarity index 60% rename from pkgs/dart_services/lib/src/compiler.dart rename to pkgs/dart_services/lib/src/compiling.dart index 0e5886fc2..758297478 100644 --- a/pkgs/dart_services/lib/src/compiler.dart +++ b/pkgs/dart_services/lib/src/compiling.dart @@ -2,9 +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. -/// This library is a wrapper around the Dart to JavaScript (dart2js) compiler. -library; - import 'dart:async'; import 'dart:io'; @@ -13,7 +10,7 @@ import 'package:logging/logging.dart'; import 'package:path/path.dart' as path; import 'common.dart'; -import 'project.dart'; +import 'project_templates.dart'; import 'pub.dart'; import 'sdk.dart'; @@ -44,8 +41,8 @@ class Compiler { maxWorkers: 1), _projectTemplates = ProjectTemplates.projectTemplates; - Future warmup({bool useHtml = false}) async { - return compile(useHtml ? sampleCodeWeb : sampleCode); + Future warmup() async { + return compile('void main() => print("hello");'); } /// Compile the given string and return the resulting [CompilationResults]. @@ -53,22 +50,9 @@ class Compiler { String source, { bool returnSourceMap = false, }) async { - return compileFiles({kMainDart: source}, returnSourceMap: returnSourceMap); - } - - /// Compile the given string and return the resulting [CompilationResults]. - Future compileFiles( - final Map files, { - bool returnSourceMap = false, - }) async { - if (files.isEmpty) { - return CompilationResults( - problems: [CompilationProblem._('file list empty')]); - } - sanitizeAndCheckFilenames(files); - final imports = getAllImportsForFiles(files); + final imports = getAllImportsFor(source); final unsupportedImports = - getUnsupportedImports(imports, sourcesFileList: files.keys.toList()); + getUnsupportedImports(imports, sourcesFileList: [kMainDart]); if (unsupportedImports.isNotEmpty) { return CompilationResults(problems: [ for (final import in unsupportedImports) @@ -76,12 +60,12 @@ class Compiler { ]); } - final temp = await Directory.systemTemp.createTemp('dartpad'); + final temp = Directory.systemTemp.createTempSync('dartpad'); _logger.fine('Temp directory created: ${temp.path}'); try { - await copyPath(_projectTemplates.dartPath, temp.path); - await Directory(path.join(temp.path, 'lib')).create(recursive: true); + _copyPath(_projectTemplates.dartPath, temp.path); + Directory(path.join(temp.path, 'lib')).createSync(recursive: true); final arguments = [ 'compile', @@ -98,10 +82,7 @@ class Compiler { path.join('lib', kMainDart), ]; - files.forEach((filename, content) async { - await File(path.join(temp.path, 'lib', filename)) - .writeAsString(content); - }); + File(path.join(temp.path, 'lib', kMainDart)).writeAsStringSync(source); final mainJs = File(path.join(temp.path, '$kMainDart.js')); final mainSourceMap = File(path.join(temp.path, '$kMainDart.js.map')); @@ -118,11 +99,11 @@ class Compiler { return results; } else { String? sourceMap; - if (returnSourceMap && await mainSourceMap.exists()) { - sourceMap = await mainSourceMap.readAsString(); + if (returnSourceMap && mainSourceMap.existsSync()) { + sourceMap = mainSourceMap.readAsStringSync(); } final results = CompilationResults( - compiledJS: await mainJs.readAsString(), + compiledJS: mainJs.readAsStringSync(), sourceMap: sourceMap, ); return results; @@ -131,31 +112,16 @@ class Compiler { _logger.warning('Compiler failed: $e\n$st'); rethrow; } finally { - await temp.delete(recursive: true); + temp.deleteSync(recursive: true); _logger.fine('temp folder removed: ${temp.path}'); } } /// Compile the given string and return the resulting [DDCCompilationResults]. Future compileDDC(String source) async { - return compileFilesDDC({kMainDart: source}); - } - - /// Compile the given set of source files and return the resulting - /// [DDCCompilationResults]. - /// - /// [files] is a map containing the source files in the format - /// `{ "filename1":"sourcecode1" ... "filenameN":"sourcecodeN"}`. - Future compileFilesDDC( - Map files) async { - if (files.isEmpty) { - return DDCCompilationResults.failed( - [CompilationProblem._('file list empty')]); - } - sanitizeAndCheckFilenames(files); - final imports = getAllImportsForFiles(files); + final imports = getAllImportsFor(source); final unsupportedImports = - getUnsupportedImports(imports, sourcesFileList: files.keys.toList()); + getUnsupportedImports(imports, sourcesFileList: [kMainDart]); if (unsupportedImports.isNotEmpty) { return DDCCompilationResults.failed([ for (final import in unsupportedImports) @@ -163,20 +129,20 @@ class Compiler { ]); } - final temp = await Directory.systemTemp.createTemp('dartpad'); + final temp = Directory.systemTemp.createTempSync('dartpad'); _logger.fine('Temp directory created: ${temp.path}'); try { final usingFlutter = usesFlutterWeb(imports); if (usesFirebase(imports)) { - await copyPath(_projectTemplates.firebasePath, temp.path); + _copyPath(_projectTemplates.firebasePath, temp.path); } else if (usingFlutter) { - await copyPath(_projectTemplates.flutterPath, temp.path); + _copyPath(_projectTemplates.flutterPath, temp.path); } else { - await copyPath(_projectTemplates.dartPath, temp.path); + _copyPath(_projectTemplates.dartPath, temp.path); } - await Directory(path.join(temp.path, 'lib')).create(recursive: true); + Directory(path.join(temp.path, 'lib')).createSync(recursive: true); final bootstrapPath = path.join(temp.path, 'lib', kBootstrapDart); String bootstrapContents; @@ -188,12 +154,8 @@ class Compiler { bootstrapContents = kBootstrapDartCode; } - await File(bootstrapPath).writeAsString(bootstrapContents); - - files.forEach((filename, content) async { - await File(path.join(temp.path, 'lib', filename)) - .writeAsString(content); - }); + File(bootstrapPath).writeAsStringSync(bootstrapContents); + File(path.join(temp.path, 'lib', kMainDart)).writeAsStringSync(source); final arguments = [ '--modules=amd', @@ -230,7 +192,8 @@ class Compiler { // adding the code to a script tag in an iframe rather than loading it // as an individual file from baseURL. As a workaround, this replace // statement injects a name into the module definition. - final processedJs = (await mainJs.readAsString()) + final processedJs = mainJs + .readAsStringSync() .replaceFirst('define([', "define('dartpad_main', ["); final results = DDCCompilationResults( @@ -244,74 +207,11 @@ class Compiler { _logger.warning('Compiler failed: $e\n$st'); rethrow; } finally { - await temp.delete(recursive: true); + temp.deleteSync(recursive: true); _logger.fine('temp folder removed: ${temp.path}'); } } - /// Compile the given source file and return the resulting - /// [FlutterBuildResults]. - Future flutterBuild(String source) async { - final unsupportedImports = getUnsupportedImports(getAllImportsFor(source)); - if (unsupportedImports.isNotEmpty) { - final message = - unsupportedImports.map((import) => import.uri.stringValue).join('\n'); - return FlutterBuildResults.failed(message); - } - - // TODO: Recycle this project directory. - final tempDir = await Directory.systemTemp.createTemp('dartpad'); - - try { - await copyPath(_projectTemplates.flutterPath, tempDir.path); - - // Update lib/main.dart. - final sourceFile = File(path.join(tempDir.path, 'lib', kMainDart)); - sourceFile.parent.createSync(); - sourceFile.writeAsStringSync(source); - - final arguments = [ - 'build', - 'web', - - // This disables minification. - '--dart2js-optimization=O1', - - // With the web renderer, we don't need to load other (skiawasm) resources. - // TODO(devoncarew): Look into use the skiawasm backend. - '--web-renderer=html', - - // This disables the service worker / caching path. - '--pwa-strategy=none', - - '--no-tree-shake-icons', - - if (_sdk.experiments.isNotEmpty) - '--enable-experiment=${_sdk.experiments.join(",")}', - ]; - - // TODO: Serialize this request - only one can run at a time. - final result = await Process.run( - _sdk.flutterToolPath, - arguments, - workingDirectory: tempDir.path, - ); - - if (result.exitCode != 0) { - return FlutterBuildResults.failed( - '${result.stdout}\n${result.stderr}'.trim()); - } - - // Return the compiled build/web/main.dart.js file. - final jsOutFile = - File(path.join(tempDir.path, 'build', 'web', 'main.dart.js')); - return FlutterBuildResults.success( - compiledJavaScript: jsOutFile.readAsStringSync()); - } finally { - await tempDir.delete(recursive: true); - } - } - Future dispose() async { return _ddcDriver.terminateWorkers(); } @@ -364,21 +264,6 @@ class DDCCompilationResults { : 'Compilation errors: ${problems.join('\n')}'; } -class FlutterBuildResults { - final String? compiledJavaScript; - final String? compilationIssues; - - FlutterBuildResults.success({required this.compiledJavaScript}) - : compilationIssues = null; - - FlutterBuildResults.failed(this.compilationIssues) - : compiledJavaScript = null; - - bool get hasOutput => compiledJavaScript != null; - - bool get success => compilationIssues == null; -} - /// An issue associated with [CompilationResults]. class CompilationProblem implements Comparable { final String message; @@ -401,19 +286,20 @@ class CompilationProblem implements Comparable { /// * If [from] and [to] are canonically the same, no operation occurs. /// /// Returns a future that completes when complete. -Future copyPath(String from, String to) async { +void _copyPath(String from, String to) { if (_doNothing(from, to)) { return; } - await Directory(to).create(recursive: true); - await for (final file in Directory(from).list(recursive: true)) { + + Directory(to).createSync(recursive: true); + for (final file in Directory(from).listSync(recursive: true)) { final copyTo = path.join(to, path.relative(file.path, from: from)); if (file is Directory) { - await Directory(copyTo).create(recursive: true); + Directory(copyTo).createSync(recursive: true); } else if (file is File) { - await File(file.path).copy(copyTo); + File(file.path).copySync(copyTo); } else if (file is Link) { - await Link(copyTo).create(await file.target(), recursive: true); + Link(copyTo).createSync(file.targetSync(), recursive: true); } } } diff --git a/pkgs/dart_services/lib/src/github_oauth_handler.dart b/pkgs/dart_services/lib/src/oauth_handler.dart similarity index 99% rename from pkgs/dart_services/lib/src/github_oauth_handler.dart rename to pkgs/dart_services/lib/src/oauth_handler.dart index 99362c607..ef0fd85ec 100644 --- a/pkgs/dart_services/lib/src/github_oauth_handler.dart +++ b/pkgs/dart_services/lib/src/oauth_handler.dart @@ -24,7 +24,7 @@ import 'package:logging/logging.dart'; import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; -import 'server_cache.dart'; +import 'caching.dart'; final Logger _logger = Logger('github_oauth_handler'); diff --git a/pkgs/dart_services/lib/src/project_creator.dart b/pkgs/dart_services/lib/src/project_creator.dart index 1e2a07c23..c11d98cdf 100644 --- a/pkgs/dart_services/lib/src/project_creator.dart +++ b/pkgs/dart_services/lib/src/project_creator.dart @@ -6,7 +6,7 @@ import 'dart:convert' show jsonDecode; import 'dart:io'; import 'package:path/path.dart' as path; -import 'project.dart'; +import 'project_templates.dart'; import 'sdk.dart'; import 'utils.dart'; @@ -48,9 +48,10 @@ class ProjectCreator { dependencies: dependencies, )); - // todo: run w/ the correct sdk final exitCode = await _runDartPubGet(projectDirectory); - if (exitCode != 0) throw StateError('pub get failed ($exitCode)'); + if (exitCode != 0) { + throw StateError('pub get failed ($exitCode)'); + } var contents = ''' include: package:lints/recommended.yaml @@ -75,8 +76,9 @@ ${_sdk.experiments.map((experiment) => ' - $experiment').join('\n')} /// Depending on [firebaseStyle], Firebase packages are included in /// `pubspec.yaml` which affects how `flutter packages get` will register /// plugins. - Future buildFlutterProjectTemplate( - {required FirebaseStyle firebaseStyle}) async { + Future buildFlutterProjectTemplate({ + required FirebaseStyle firebaseStyle, + }) async { final projectDirName = firebaseStyle == FirebaseStyle.none ? 'flutter_project' : 'firebase_project'; @@ -103,12 +105,10 @@ ${_sdk.experiments.map((experiment) => ' - $experiment').join('\n')} dependencies: dependencies, )); - final exitCode = await runFlutterPackagesGet( - _sdk.flutterToolPath, - projectPath, - log: _log, - ); - if (exitCode != 0) throw StateError('flutter pub get failed ($exitCode)'); + final exitCode = await runFlutterPubGet(_sdk, projectPath, log: _log); + if (exitCode != 0) { + throw StateError('flutter pub get failed ($exitCode)'); + } // Working around Flutter 3.3's deprecation of generated_plugin_registrant.dart // Context: https://github.com/flutter/flutter/pull/106921 @@ -139,15 +139,15 @@ ${_sdk.experiments.map((experiment) => ' - $experiment').join('\n')} dependencies: dependencies, )); - final exitCode = await runFlutterPackagesGet( - _sdk.flutterToolPath, - projectPath, - log: _log, - ); - if (exitCode != 0) throw StateError('flutter pub get failed ($exitCode)'); + final exitCode = await runFlutterPubGet(_sdk, projectPath, log: _log); + if (exitCode != 0) { + throw StateError('flutter pub get failed ($exitCode)'); + } } + var contents = ''' include: package:flutter_lints/flutter.yaml + linter: rules: avoid_print: false @@ -155,6 +155,7 @@ linter: '''; if (_sdk.experiments.isNotEmpty) { contents += ''' + analyzer: enable-experiment: ${_sdk.experiments.map((experiment) => ' - $experiment').join('\n')} @@ -238,16 +239,18 @@ dependencies: return content; } -Future runFlutterPackagesGet( - String flutterToolPath, +Future runFlutterPubGet( + Sdk sdk, String projectPath, { required LogFunction log, }) async { - final process = await runWithLogging(flutterToolPath, - arguments: ['packages', 'get'], - workingDirectory: projectPath, - environment: {'PUB_CACHE': _pubCachePath}, - log: log); + final process = await runWithLogging( + sdk.flutterToolPath, + arguments: ['pub', 'get'], + workingDirectory: projectPath, + environment: {'PUB_CACHE': _pubCachePath}, + log: log, + ); return process.exitCode; } diff --git a/pkgs/dart_services/lib/src/project.dart b/pkgs/dart_services/lib/src/project_templates.dart similarity index 97% rename from pkgs/dart_services/lib/src/project.dart rename to pkgs/dart_services/lib/src/project_templates.dart index b8f5324f6..091133d98 100644 --- a/pkgs/dart_services/lib/src/project.dart +++ b/pkgs/dart_services/lib/src/project_templates.dart @@ -200,15 +200,15 @@ String? _packageNameFromPackageUri(String uriString) { } /// Goes through imports list and returns list of unsupported imports. +/// /// Optional [sourcesFileList] contains a list of the source filenames /// which are all part of this overall sources file set (these are to /// be allowed). +/// /// Note: The filenames in [sourcesFileList] were sanitized of any -/// 'package:'/etc syntax as the file set arrives from the endpoint, -/// and before being passed to [getUnsupportedImports]. -/// This is done so the list can't be used to bypass unsupported imports. -/// The function [sanitizeAndCheckFilenames()] was used to sanitize the -/// filenames. +/// 'package:'/etc syntax as the file set arrives from the endpoint, and before +/// being passed to [getUnsupportedImports]. This is done so the list can't be +/// used to bypass unsupported imports. List getUnsupportedImports( List imports, { List? sourcesFileList, diff --git a/pkgs/dart_services/lib/src/protos/dart_services.pb.dart b/pkgs/dart_services/lib/src/protos/dart_services.pb.dart deleted file mode 100644 index bb16c423e..000000000 --- a/pkgs/dart_services/lib/src/protos/dart_services.pb.dart +++ /dev/null @@ -1,2764 +0,0 @@ -// -// Generated code. Do not modify. -// source: protos/dart_services.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -import 'dart:core' as $core; - -import 'package:protobuf/protobuf.dart' as $pb; - -class CompileRequest extends $pb.GeneratedMessage { - factory CompileRequest({ - $core.String? source, - $core.bool? returnSourceMap, - }) { - final $result = create(); - if (source != null) { - $result.source = source; - } - if (returnSourceMap != null) { - $result.returnSourceMap = returnSourceMap; - } - return $result; - } - CompileRequest._() : super(); - factory CompileRequest.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory CompileRequest.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'CompileRequest', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'source') - ..aOB(2, _omitFieldNames ? '' : 'returnSourceMap', - protoName: 'returnSourceMap') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CompileRequest clone() => CompileRequest()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CompileRequest copyWith(void Function(CompileRequest) updates) => - super.copyWith((message) => updates(message as CompileRequest)) - as CompileRequest; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static CompileRequest create() => CompileRequest._(); - CompileRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CompileRequest getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static CompileRequest? _defaultInstance; - - /// The Dart source. - @$pb.TagNumber(1) - $core.String get source => $_getSZ(0); - @$pb.TagNumber(1) - set source($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasSource() => $_has(0); - @$pb.TagNumber(1) - void clearSource() => clearField(1); - - /// Return the Dart to JS source map; optional (defaults to false). - @$pb.TagNumber(2) - $core.bool get returnSourceMap => $_getBF(1); - @$pb.TagNumber(2) - set returnSourceMap($core.bool v) { - $_setBool(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasReturnSourceMap() => $_has(1); - @$pb.TagNumber(2) - void clearReturnSourceMap() => clearField(2); -} - -/// / Compile request for a multiple file set. -class CompileFilesRequest extends $pb.GeneratedMessage { - factory CompileFilesRequest({ - $core.Map<$core.String, $core.String>? files, - $core.bool? returnSourceMap, - }) { - final $result = create(); - if (files != null) { - $result.files.addAll(files); - } - if (returnSourceMap != null) { - $result.returnSourceMap = returnSourceMap; - } - return $result; - } - CompileFilesRequest._() : super(); - factory CompileFilesRequest.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory CompileFilesRequest.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'CompileFilesRequest', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..m<$core.String, $core.String>(1, _omitFieldNames ? '' : 'files', - entryClassName: 'CompileFilesRequest.FilesEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('dart_services.api')) - ..aOB(2, _omitFieldNames ? '' : 'returnSourceMap', - protoName: 'returnSourceMap') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CompileFilesRequest clone() => CompileFilesRequest()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CompileFilesRequest copyWith(void Function(CompileFilesRequest) updates) => - super.copyWith((message) => updates(message as CompileFilesRequest)) - as CompileFilesRequest; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static CompileFilesRequest create() => CompileFilesRequest._(); - CompileFilesRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CompileFilesRequest getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static CompileFilesRequest? _defaultInstance; - - /// The Dart source files set. map of { filename1:sourcecode1 .. filenameN:sourcecodeN } - @$pb.TagNumber(1) - $core.Map<$core.String, $core.String> get files => $_getMap(0); - - /// Return the Dart to JS source map; optional (defaults to false). - @$pb.TagNumber(2) - $core.bool get returnSourceMap => $_getBF(1); - @$pb.TagNumber(2) - set returnSourceMap($core.bool v) { - $_setBool(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasReturnSourceMap() => $_has(1); - @$pb.TagNumber(2) - void clearReturnSourceMap() => clearField(2); -} - -class CompileDDCRequest extends $pb.GeneratedMessage { - factory CompileDDCRequest({ - $core.String? source, - }) { - final $result = create(); - if (source != null) { - $result.source = source; - } - return $result; - } - CompileDDCRequest._() : super(); - factory CompileDDCRequest.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory CompileDDCRequest.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'CompileDDCRequest', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'source') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CompileDDCRequest clone() => CompileDDCRequest()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CompileDDCRequest copyWith(void Function(CompileDDCRequest) updates) => - super.copyWith((message) => updates(message as CompileDDCRequest)) - as CompileDDCRequest; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static CompileDDCRequest create() => CompileDDCRequest._(); - CompileDDCRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CompileDDCRequest getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static CompileDDCRequest? _defaultInstance; - - /// The Dart source. - @$pb.TagNumber(1) - $core.String get source => $_getSZ(0); - @$pb.TagNumber(1) - set source($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasSource() => $_has(0); - @$pb.TagNumber(1) - void clearSource() => clearField(1); -} - -/// / DDC Compile request for a multiple file set. -class CompileFilesDDCRequest extends $pb.GeneratedMessage { - factory CompileFilesDDCRequest({ - $core.Map<$core.String, $core.String>? files, - }) { - final $result = create(); - if (files != null) { - $result.files.addAll(files); - } - return $result; - } - CompileFilesDDCRequest._() : super(); - factory CompileFilesDDCRequest.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory CompileFilesDDCRequest.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'CompileFilesDDCRequest', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..m<$core.String, $core.String>(1, _omitFieldNames ? '' : 'files', - entryClassName: 'CompileFilesDDCRequest.FilesEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('dart_services.api')) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CompileFilesDDCRequest clone() => - CompileFilesDDCRequest()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CompileFilesDDCRequest copyWith( - void Function(CompileFilesDDCRequest) updates) => - super.copyWith((message) => updates(message as CompileFilesDDCRequest)) - as CompileFilesDDCRequest; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static CompileFilesDDCRequest create() => CompileFilesDDCRequest._(); - CompileFilesDDCRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CompileFilesDDCRequest getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static CompileFilesDDCRequest? _defaultInstance; - - /// The Dart source files set. map of { filename1:sourcecode1 .. filenameN:sourcecodeN } - @$pb.TagNumber(1) - $core.Map<$core.String, $core.String> get files => $_getMap(0); -} - -class FlutterBuildResponse extends $pb.GeneratedMessage { - factory FlutterBuildResponse({ - $core.Map<$core.String, $core.String>? artifacts, - ErrorMessage? error, - }) { - final $result = create(); - if (artifacts != null) { - $result.artifacts.addAll(artifacts); - } - if (error != null) { - $result.error = error; - } - return $result; - } - FlutterBuildResponse._() : super(); - factory FlutterBuildResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory FlutterBuildResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'FlutterBuildResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..m<$core.String, $core.String>(1, _omitFieldNames ? '' : 'artifacts', - entryClassName: 'FlutterBuildResponse.ArtifactsEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('dart_services.api')) - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - FlutterBuildResponse clone() => - FlutterBuildResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - FlutterBuildResponse copyWith(void Function(FlutterBuildResponse) updates) => - super.copyWith((message) => updates(message as FlutterBuildResponse)) - as FlutterBuildResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static FlutterBuildResponse create() => FlutterBuildResponse._(); - FlutterBuildResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static FlutterBuildResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static FlutterBuildResponse? _defaultInstance; - - @$pb.TagNumber(1) - $core.Map<$core.String, $core.String> get artifacts => $_getMap(0); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(1); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(1); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(1); -} - -class SourceRequest extends $pb.GeneratedMessage { - factory SourceRequest({ - $core.String? source, - $core.int? offset, - }) { - final $result = create(); - if (source != null) { - $result.source = source; - } - if (offset != null) { - $result.offset = offset; - } - return $result; - } - SourceRequest._() : super(); - factory SourceRequest.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory SourceRequest.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'SourceRequest', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'source') - ..a<$core.int>(2, _omitFieldNames ? '' : 'offset', $pb.PbFieldType.O3) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - SourceRequest clone() => SourceRequest()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - SourceRequest copyWith(void Function(SourceRequest) updates) => - super.copyWith((message) => updates(message as SourceRequest)) - as SourceRequest; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static SourceRequest create() => SourceRequest._(); - SourceRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static SourceRequest getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static SourceRequest? _defaultInstance; - - /// The Dart source. - @$pb.TagNumber(1) - $core.String get source => $_getSZ(0); - @$pb.TagNumber(1) - set source($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasSource() => $_has(0); - @$pb.TagNumber(1) - void clearSource() => clearField(1); - - /// The offset within source to operate at. - @$pb.TagNumber(2) - $core.int get offset => $_getIZ(1); - @$pb.TagNumber(2) - set offset($core.int v) { - $_setSignedInt32(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasOffset() => $_has(1); - @$pb.TagNumber(2) - void clearOffset() => clearField(2); -} - -/// / Multiple file set of dart source for analysis, completion, fixes, etc. -class SourceFilesRequest extends $pb.GeneratedMessage { - factory SourceFilesRequest({ - $core.Map<$core.String, $core.String>? files, - $core.String? activeSourceName, - $core.int? offset, - }) { - final $result = create(); - if (files != null) { - $result.files.addAll(files); - } - if (activeSourceName != null) { - $result.activeSourceName = activeSourceName; - } - if (offset != null) { - $result.offset = offset; - } - return $result; - } - SourceFilesRequest._() : super(); - factory SourceFilesRequest.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory SourceFilesRequest.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'SourceFilesRequest', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..m<$core.String, $core.String>(1, _omitFieldNames ? '' : 'files', - entryClassName: 'SourceFilesRequest.FilesEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('dart_services.api')) - ..aOS(2, _omitFieldNames ? '' : 'activeSourceName', - protoName: 'activeSourceName') - ..a<$core.int>(3, _omitFieldNames ? '' : 'offset', $pb.PbFieldType.O3) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - SourceFilesRequest clone() => SourceFilesRequest()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - SourceFilesRequest copyWith(void Function(SourceFilesRequest) updates) => - super.copyWith((message) => updates(message as SourceFilesRequest)) - as SourceFilesRequest; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static SourceFilesRequest create() => SourceFilesRequest._(); - SourceFilesRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static SourceFilesRequest getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static SourceFilesRequest? _defaultInstance; - - /// The Dart source files set. map of { filename1:sourcecode1 .. filenameN:sourcecodeN } - @$pb.TagNumber(1) - $core.Map<$core.String, $core.String> get files => $_getMap(0); - - /// active (within editor) source filename key within files map - @$pb.TagNumber(2) - $core.String get activeSourceName => $_getSZ(1); - @$pb.TagNumber(2) - set activeSourceName($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasActiveSourceName() => $_has(1); - @$pb.TagNumber(2) - void clearActiveSourceName() => clearField(2); - - /// The offset within active source file to operate at. - @$pb.TagNumber(3) - $core.int get offset => $_getIZ(2); - @$pb.TagNumber(3) - set offset($core.int v) { - $_setSignedInt32(2, v); - } - - @$pb.TagNumber(3) - $core.bool hasOffset() => $_has(2); - @$pb.TagNumber(3) - void clearOffset() => clearField(3); -} - -class AnalysisResults extends $pb.GeneratedMessage { - factory AnalysisResults({ - $core.Iterable? issues, - $core.Iterable<$core.String>? packageImports, - ErrorMessage? error, - }) { - final $result = create(); - if (issues != null) { - $result.issues.addAll(issues); - } - if (packageImports != null) { - $result.packageImports.addAll(packageImports); - } - if (error != null) { - $result.error = error; - } - return $result; - } - AnalysisResults._() : super(); - factory AnalysisResults.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory AnalysisResults.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'AnalysisResults', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..pc(1, _omitFieldNames ? '' : 'issues', $pb.PbFieldType.PM, - subBuilder: AnalysisIssue.create) - ..pPS(2, _omitFieldNames ? '' : 'packageImports', - protoName: 'packageImports') - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - AnalysisResults clone() => AnalysisResults()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - AnalysisResults copyWith(void Function(AnalysisResults) updates) => - super.copyWith((message) => updates(message as AnalysisResults)) - as AnalysisResults; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static AnalysisResults create() => AnalysisResults._(); - AnalysisResults createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static AnalysisResults getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static AnalysisResults? _defaultInstance; - - @$pb.TagNumber(1) - $core.List get issues => $_getList(0); - - /// The package imports parsed from the source. - @$pb.TagNumber(2) - $core.List<$core.String> get packageImports => $_getList(1); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(2); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(2); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(2); -} - -class AnalysisIssue extends $pb.GeneratedMessage { - factory AnalysisIssue({ - $core.String? kind, - $core.int? line, - $core.String? message, - $core.String? sourceName, - $core.bool? hasFixes, - $core.int? charStart, - $core.int? charLength, - $core.String? url, - $core.Iterable? diagnosticMessages, - $core.String? correction, - $core.int? column, - $core.String? code, - }) { - final $result = create(); - if (kind != null) { - $result.kind = kind; - } - if (line != null) { - $result.line = line; - } - if (message != null) { - $result.message = message; - } - if (sourceName != null) { - $result.sourceName = sourceName; - } - if (hasFixes != null) { - $result.hasFixes = hasFixes; - } - if (charStart != null) { - $result.charStart = charStart; - } - if (charLength != null) { - $result.charLength = charLength; - } - if (url != null) { - $result.url = url; - } - if (diagnosticMessages != null) { - $result.diagnosticMessages.addAll(diagnosticMessages); - } - if (correction != null) { - $result.correction = correction; - } - if (column != null) { - $result.column = column; - } - if (code != null) { - $result.code = code; - } - return $result; - } - AnalysisIssue._() : super(); - factory AnalysisIssue.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory AnalysisIssue.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'AnalysisIssue', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'kind') - ..a<$core.int>(2, _omitFieldNames ? '' : 'line', $pb.PbFieldType.O3) - ..aOS(3, _omitFieldNames ? '' : 'message') - ..aOS(4, _omitFieldNames ? '' : 'sourceName', protoName: 'sourceName') - ..aOB(5, _omitFieldNames ? '' : 'hasFixes', protoName: 'hasFixes') - ..a<$core.int>(6, _omitFieldNames ? '' : 'charStart', $pb.PbFieldType.O3, - protoName: 'charStart') - ..a<$core.int>(7, _omitFieldNames ? '' : 'charLength', $pb.PbFieldType.O3, - protoName: 'charLength') - ..aOS(8, _omitFieldNames ? '' : 'url') - ..pc( - 9, _omitFieldNames ? '' : 'diagnosticMessages', $pb.PbFieldType.PM, - protoName: 'diagnosticMessages', subBuilder: DiagnosticMessage.create) - ..aOS(10, _omitFieldNames ? '' : 'correction') - ..a<$core.int>(11, _omitFieldNames ? '' : 'column', $pb.PbFieldType.O3) - ..aOS(12, _omitFieldNames ? '' : 'code') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - AnalysisIssue clone() => AnalysisIssue()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - AnalysisIssue copyWith(void Function(AnalysisIssue) updates) => - super.copyWith((message) => updates(message as AnalysisIssue)) - as AnalysisIssue; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static AnalysisIssue create() => AnalysisIssue._(); - AnalysisIssue createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static AnalysisIssue getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static AnalysisIssue? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get kind => $_getSZ(0); - @$pb.TagNumber(1) - set kind($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasKind() => $_has(0); - @$pb.TagNumber(1) - void clearKind() => clearField(1); - - @$pb.TagNumber(2) - $core.int get line => $_getIZ(1); - @$pb.TagNumber(2) - set line($core.int v) { - $_setSignedInt32(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasLine() => $_has(1); - @$pb.TagNumber(2) - void clearLine() => clearField(2); - - @$pb.TagNumber(3) - $core.String get message => $_getSZ(2); - @$pb.TagNumber(3) - set message($core.String v) { - $_setString(2, v); - } - - @$pb.TagNumber(3) - $core.bool hasMessage() => $_has(2); - @$pb.TagNumber(3) - void clearMessage() => clearField(3); - - @$pb.TagNumber(4) - $core.String get sourceName => $_getSZ(3); - @$pb.TagNumber(4) - set sourceName($core.String v) { - $_setString(3, v); - } - - @$pb.TagNumber(4) - $core.bool hasSourceName() => $_has(3); - @$pb.TagNumber(4) - void clearSourceName() => clearField(4); - - @$pb.TagNumber(5) - $core.bool get hasFixes => $_getBF(4); - @$pb.TagNumber(5) - set hasFixes($core.bool v) { - $_setBool(4, v); - } - - @$pb.TagNumber(5) - $core.bool hasHasFixes() => $_has(4); - @$pb.TagNumber(5) - void clearHasFixes() => clearField(5); - - @$pb.TagNumber(6) - $core.int get charStart => $_getIZ(5); - @$pb.TagNumber(6) - set charStart($core.int v) { - $_setSignedInt32(5, v); - } - - @$pb.TagNumber(6) - $core.bool hasCharStart() => $_has(5); - @$pb.TagNumber(6) - void clearCharStart() => clearField(6); - - @$pb.TagNumber(7) - $core.int get charLength => $_getIZ(6); - @$pb.TagNumber(7) - set charLength($core.int v) { - $_setSignedInt32(6, v); - } - - @$pb.TagNumber(7) - $core.bool hasCharLength() => $_has(6); - @$pb.TagNumber(7) - void clearCharLength() => clearField(7); - - @$pb.TagNumber(8) - $core.String get url => $_getSZ(7); - @$pb.TagNumber(8) - set url($core.String v) { - $_setString(7, v); - } - - @$pb.TagNumber(8) - $core.bool hasUrl() => $_has(7); - @$pb.TagNumber(8) - void clearUrl() => clearField(8); - - @$pb.TagNumber(9) - $core.List get diagnosticMessages => $_getList(8); - - @$pb.TagNumber(10) - $core.String get correction => $_getSZ(9); - @$pb.TagNumber(10) - set correction($core.String v) { - $_setString(9, v); - } - - @$pb.TagNumber(10) - $core.bool hasCorrection() => $_has(9); - @$pb.TagNumber(10) - void clearCorrection() => clearField(10); - - @$pb.TagNumber(11) - $core.int get column => $_getIZ(10); - @$pb.TagNumber(11) - set column($core.int v) { - $_setSignedInt32(10, v); - } - - @$pb.TagNumber(11) - $core.bool hasColumn() => $_has(10); - @$pb.TagNumber(11) - void clearColumn() => clearField(11); - - @$pb.TagNumber(12) - $core.String get code => $_getSZ(11); - @$pb.TagNumber(12) - set code($core.String v) { - $_setString(11, v); - } - - @$pb.TagNumber(12) - $core.bool hasCode() => $_has(11); - @$pb.TagNumber(12) - void clearCode() => clearField(12); -} - -class DiagnosticMessage extends $pb.GeneratedMessage { - factory DiagnosticMessage({ - $core.String? message, - $core.int? line, - $core.int? charStart, - $core.int? charLength, - $core.int? column, - }) { - final $result = create(); - if (message != null) { - $result.message = message; - } - if (line != null) { - $result.line = line; - } - if (charStart != null) { - $result.charStart = charStart; - } - if (charLength != null) { - $result.charLength = charLength; - } - if (column != null) { - $result.column = column; - } - return $result; - } - DiagnosticMessage._() : super(); - factory DiagnosticMessage.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory DiagnosticMessage.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'DiagnosticMessage', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'message') - ..a<$core.int>(2, _omitFieldNames ? '' : 'line', $pb.PbFieldType.O3) - ..a<$core.int>(3, _omitFieldNames ? '' : 'charStart', $pb.PbFieldType.O3, - protoName: 'charStart') - ..a<$core.int>(4, _omitFieldNames ? '' : 'charLength', $pb.PbFieldType.O3, - protoName: 'charLength') - ..a<$core.int>(5, _omitFieldNames ? '' : 'column', $pb.PbFieldType.O3) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - DiagnosticMessage clone() => DiagnosticMessage()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - DiagnosticMessage copyWith(void Function(DiagnosticMessage) updates) => - super.copyWith((message) => updates(message as DiagnosticMessage)) - as DiagnosticMessage; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static DiagnosticMessage create() => DiagnosticMessage._(); - DiagnosticMessage createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static DiagnosticMessage getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static DiagnosticMessage? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get message => $_getSZ(0); - @$pb.TagNumber(1) - set message($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasMessage() => $_has(0); - @$pb.TagNumber(1) - void clearMessage() => clearField(1); - - @$pb.TagNumber(2) - $core.int get line => $_getIZ(1); - @$pb.TagNumber(2) - set line($core.int v) { - $_setSignedInt32(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasLine() => $_has(1); - @$pb.TagNumber(2) - void clearLine() => clearField(2); - - @$pb.TagNumber(3) - $core.int get charStart => $_getIZ(2); - @$pb.TagNumber(3) - set charStart($core.int v) { - $_setSignedInt32(2, v); - } - - @$pb.TagNumber(3) - $core.bool hasCharStart() => $_has(2); - @$pb.TagNumber(3) - void clearCharStart() => clearField(3); - - @$pb.TagNumber(4) - $core.int get charLength => $_getIZ(3); - @$pb.TagNumber(4) - set charLength($core.int v) { - $_setSignedInt32(3, v); - } - - @$pb.TagNumber(4) - $core.bool hasCharLength() => $_has(3); - @$pb.TagNumber(4) - void clearCharLength() => clearField(4); - - @$pb.TagNumber(5) - $core.int get column => $_getIZ(4); - @$pb.TagNumber(5) - set column($core.int v) { - $_setSignedInt32(4, v); - } - - @$pb.TagNumber(5) - $core.bool hasColumn() => $_has(4); - @$pb.TagNumber(5) - void clearColumn() => clearField(5); -} - -class VersionRequest extends $pb.GeneratedMessage { - factory VersionRequest() => create(); - VersionRequest._() : super(); - factory VersionRequest.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory VersionRequest.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'VersionRequest', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - VersionRequest clone() => VersionRequest()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - VersionRequest copyWith(void Function(VersionRequest) updates) => - super.copyWith((message) => updates(message as VersionRequest)) - as VersionRequest; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static VersionRequest create() => VersionRequest._(); - VersionRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static VersionRequest getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static VersionRequest? _defaultInstance; -} - -class CompileResponse extends $pb.GeneratedMessage { - factory CompileResponse({ - $core.String? result, - $core.String? sourceMap, - ErrorMessage? error, - }) { - final $result = create(); - if (result != null) { - $result.result = result; - } - if (sourceMap != null) { - $result.sourceMap = sourceMap; - } - if (error != null) { - $result.error = error; - } - return $result; - } - CompileResponse._() : super(); - factory CompileResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory CompileResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'CompileResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'result') - ..aOS(2, _omitFieldNames ? '' : 'sourceMap', protoName: 'sourceMap') - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CompileResponse clone() => CompileResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CompileResponse copyWith(void Function(CompileResponse) updates) => - super.copyWith((message) => updates(message as CompileResponse)) - as CompileResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static CompileResponse create() => CompileResponse._(); - CompileResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CompileResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static CompileResponse? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get result => $_getSZ(0); - @$pb.TagNumber(1) - set result($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasResult() => $_has(0); - @$pb.TagNumber(1) - void clearResult() => clearField(1); - - @$pb.TagNumber(2) - $core.String get sourceMap => $_getSZ(1); - @$pb.TagNumber(2) - set sourceMap($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasSourceMap() => $_has(1); - @$pb.TagNumber(2) - void clearSourceMap() => clearField(2); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(2); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(2); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(2); -} - -class CompileDDCResponse extends $pb.GeneratedMessage { - factory CompileDDCResponse({ - $core.String? result, - $core.String? modulesBaseUrl, - ErrorMessage? error, - }) { - final $result = create(); - if (result != null) { - $result.result = result; - } - if (modulesBaseUrl != null) { - $result.modulesBaseUrl = modulesBaseUrl; - } - if (error != null) { - $result.error = error; - } - return $result; - } - CompileDDCResponse._() : super(); - factory CompileDDCResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory CompileDDCResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'CompileDDCResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'result') - ..aOS(2, _omitFieldNames ? '' : 'modulesBaseUrl', - protoName: 'modulesBaseUrl') - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CompileDDCResponse clone() => CompileDDCResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CompileDDCResponse copyWith(void Function(CompileDDCResponse) updates) => - super.copyWith((message) => updates(message as CompileDDCResponse)) - as CompileDDCResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static CompileDDCResponse create() => CompileDDCResponse._(); - CompileDDCResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CompileDDCResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static CompileDDCResponse? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get result => $_getSZ(0); - @$pb.TagNumber(1) - set result($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasResult() => $_has(0); - @$pb.TagNumber(1) - void clearResult() => clearField(1); - - @$pb.TagNumber(2) - $core.String get modulesBaseUrl => $_getSZ(1); - @$pb.TagNumber(2) - set modulesBaseUrl($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasModulesBaseUrl() => $_has(1); - @$pb.TagNumber(2) - void clearModulesBaseUrl() => clearField(2); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(2); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(2); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(2); -} - -class DocumentResponse extends $pb.GeneratedMessage { - factory DocumentResponse({ - $core.Map<$core.String, $core.String>? info, - ErrorMessage? error, - }) { - final $result = create(); - if (info != null) { - $result.info.addAll(info); - } - if (error != null) { - $result.error = error; - } - return $result; - } - DocumentResponse._() : super(); - factory DocumentResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory DocumentResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'DocumentResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..m<$core.String, $core.String>(1, _omitFieldNames ? '' : 'info', - entryClassName: 'DocumentResponse.InfoEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('dart_services.api')) - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - DocumentResponse clone() => DocumentResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - DocumentResponse copyWith(void Function(DocumentResponse) updates) => - super.copyWith((message) => updates(message as DocumentResponse)) - as DocumentResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static DocumentResponse create() => DocumentResponse._(); - DocumentResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static DocumentResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static DocumentResponse? _defaultInstance; - - @$pb.TagNumber(1) - $core.Map<$core.String, $core.String> get info => $_getMap(0); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(1); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(1); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(1); -} - -class CompleteResponse extends $pb.GeneratedMessage { - factory CompleteResponse({ - $core.int? replacementOffset, - $core.int? replacementLength, - $core.Iterable? completions, - ErrorMessage? error, - }) { - final $result = create(); - if (replacementOffset != null) { - $result.replacementOffset = replacementOffset; - } - if (replacementLength != null) { - $result.replacementLength = replacementLength; - } - if (completions != null) { - $result.completions.addAll(completions); - } - if (error != null) { - $result.error = error; - } - return $result; - } - CompleteResponse._() : super(); - factory CompleteResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory CompleteResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'CompleteResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..a<$core.int>( - 1, _omitFieldNames ? '' : 'replacementOffset', $pb.PbFieldType.O3, - protoName: 'replacementOffset') - ..a<$core.int>( - 2, _omitFieldNames ? '' : 'replacementLength', $pb.PbFieldType.O3, - protoName: 'replacementLength') - ..pc( - 3, _omitFieldNames ? '' : 'completions', $pb.PbFieldType.PM, - subBuilder: Completion.create) - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CompleteResponse clone() => CompleteResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CompleteResponse copyWith(void Function(CompleteResponse) updates) => - super.copyWith((message) => updates(message as CompleteResponse)) - as CompleteResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static CompleteResponse create() => CompleteResponse._(); - CompleteResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CompleteResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static CompleteResponse? _defaultInstance; - - /// The offset of the start of the text to be replaced. - @$pb.TagNumber(1) - $core.int get replacementOffset => $_getIZ(0); - @$pb.TagNumber(1) - set replacementOffset($core.int v) { - $_setSignedInt32(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasReplacementOffset() => $_has(0); - @$pb.TagNumber(1) - void clearReplacementOffset() => clearField(1); - - /// The length of the text to be replaced. - @$pb.TagNumber(2) - $core.int get replacementLength => $_getIZ(1); - @$pb.TagNumber(2) - set replacementLength($core.int v) { - $_setSignedInt32(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasReplacementLength() => $_has(1); - @$pb.TagNumber(2) - void clearReplacementLength() => clearField(2); - - @$pb.TagNumber(3) - $core.List get completions => $_getList(2); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(3); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(3); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(3); -} - -class Completion extends $pb.GeneratedMessage { - factory Completion({ - $core.Map<$core.String, $core.String>? completion, - }) { - final $result = create(); - if (completion != null) { - $result.completion.addAll(completion); - } - return $result; - } - Completion._() : super(); - factory Completion.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory Completion.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'Completion', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..m<$core.String, $core.String>(1, _omitFieldNames ? '' : 'completion', - entryClassName: 'Completion.CompletionEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('dart_services.api')) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - Completion clone() => Completion()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - Completion copyWith(void Function(Completion) updates) => - super.copyWith((message) => updates(message as Completion)) as Completion; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static Completion create() => Completion._(); - Completion createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static Completion getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static Completion? _defaultInstance; - - @$pb.TagNumber(1) - $core.Map<$core.String, $core.String> get completion => $_getMap(0); -} - -class FixesResponse extends $pb.GeneratedMessage { - factory FixesResponse({ - $core.Iterable? fixes, - ErrorMessage? error, - }) { - final $result = create(); - if (fixes != null) { - $result.fixes.addAll(fixes); - } - if (error != null) { - $result.error = error; - } - return $result; - } - FixesResponse._() : super(); - factory FixesResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory FixesResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'FixesResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..pc(1, _omitFieldNames ? '' : 'fixes', $pb.PbFieldType.PM, - subBuilder: ProblemAndFixes.create) - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - FixesResponse clone() => FixesResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - FixesResponse copyWith(void Function(FixesResponse) updates) => - super.copyWith((message) => updates(message as FixesResponse)) - as FixesResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static FixesResponse create() => FixesResponse._(); - FixesResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static FixesResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static FixesResponse? _defaultInstance; - - @$pb.TagNumber(1) - $core.List get fixes => $_getList(0); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(1); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(1); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(1); -} - -/// Represents a problem detected during analysis, and a set of possible ways of -/// resolving the problem. -class ProblemAndFixes extends $pb.GeneratedMessage { - factory ProblemAndFixes({ - $core.Iterable? fixes, - $core.String? problemMessage, - $core.int? offset, - $core.int? length, - }) { - final $result = create(); - if (fixes != null) { - $result.fixes.addAll(fixes); - } - if (problemMessage != null) { - $result.problemMessage = problemMessage; - } - if (offset != null) { - $result.offset = offset; - } - if (length != null) { - $result.length = length; - } - return $result; - } - ProblemAndFixes._() : super(); - factory ProblemAndFixes.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory ProblemAndFixes.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'ProblemAndFixes', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..pc(1, _omitFieldNames ? '' : 'fixes', $pb.PbFieldType.PM, - subBuilder: CandidateFix.create) - ..aOS(2, _omitFieldNames ? '' : 'problemMessage', - protoName: 'problemMessage') - ..a<$core.int>(3, _omitFieldNames ? '' : 'offset', $pb.PbFieldType.O3) - ..a<$core.int>(4, _omitFieldNames ? '' : 'length', $pb.PbFieldType.O3) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - ProblemAndFixes clone() => ProblemAndFixes()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - ProblemAndFixes copyWith(void Function(ProblemAndFixes) updates) => - super.copyWith((message) => updates(message as ProblemAndFixes)) - as ProblemAndFixes; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static ProblemAndFixes create() => ProblemAndFixes._(); - ProblemAndFixes createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static ProblemAndFixes getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static ProblemAndFixes? _defaultInstance; - - @$pb.TagNumber(1) - $core.List get fixes => $_getList(0); - - @$pb.TagNumber(2) - $core.String get problemMessage => $_getSZ(1); - @$pb.TagNumber(2) - set problemMessage($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasProblemMessage() => $_has(1); - @$pb.TagNumber(2) - void clearProblemMessage() => clearField(2); - - @$pb.TagNumber(3) - $core.int get offset => $_getIZ(2); - @$pb.TagNumber(3) - set offset($core.int v) { - $_setSignedInt32(2, v); - } - - @$pb.TagNumber(3) - $core.bool hasOffset() => $_has(2); - @$pb.TagNumber(3) - void clearOffset() => clearField(3); - - @$pb.TagNumber(4) - $core.int get length => $_getIZ(3); - @$pb.TagNumber(4) - set length($core.int v) { - $_setSignedInt32(3, v); - } - - @$pb.TagNumber(4) - $core.bool hasLength() => $_has(3); - @$pb.TagNumber(4) - void clearLength() => clearField(4); -} - -/// Represents a possible way of solving an Analysis Problem. -class CandidateFix extends $pb.GeneratedMessage { - factory CandidateFix({ - $core.String? message, - $core.Iterable? edits, - $core.int? selectionOffset, - $core.Iterable? linkedEditGroups, - }) { - final $result = create(); - if (message != null) { - $result.message = message; - } - if (edits != null) { - $result.edits.addAll(edits); - } - if (selectionOffset != null) { - $result.selectionOffset = selectionOffset; - } - if (linkedEditGroups != null) { - $result.linkedEditGroups.addAll(linkedEditGroups); - } - return $result; - } - CandidateFix._() : super(); - factory CandidateFix.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory CandidateFix.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'CandidateFix', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'message') - ..pc(2, _omitFieldNames ? '' : 'edits', $pb.PbFieldType.PM, - subBuilder: SourceEdit.create) - ..a<$core.int>( - 3, _omitFieldNames ? '' : 'selectionOffset', $pb.PbFieldType.O3, - protoName: 'selectionOffset') - ..pc( - 4, _omitFieldNames ? '' : 'linkedEditGroups', $pb.PbFieldType.PM, - protoName: 'linkedEditGroups', subBuilder: LinkedEditGroup.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CandidateFix clone() => CandidateFix()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CandidateFix copyWith(void Function(CandidateFix) updates) => - super.copyWith((message) => updates(message as CandidateFix)) - as CandidateFix; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static CandidateFix create() => CandidateFix._(); - CandidateFix createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CandidateFix getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static CandidateFix? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get message => $_getSZ(0); - @$pb.TagNumber(1) - set message($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasMessage() => $_has(0); - @$pb.TagNumber(1) - void clearMessage() => clearField(1); - - @$pb.TagNumber(2) - $core.List get edits => $_getList(1); - - @$pb.TagNumber(3) - $core.int get selectionOffset => $_getIZ(2); - @$pb.TagNumber(3) - set selectionOffset($core.int v) { - $_setSignedInt32(2, v); - } - - @$pb.TagNumber(3) - $core.bool hasSelectionOffset() => $_has(2); - @$pb.TagNumber(3) - void clearSelectionOffset() => clearField(3); - - @$pb.TagNumber(4) - $core.List get linkedEditGroups => $_getList(3); -} - -/// Represents a single edit-point change to a source file. -class SourceEdit extends $pb.GeneratedMessage { - factory SourceEdit({ - $core.int? offset, - $core.int? length, - $core.String? replacement, - }) { - final $result = create(); - if (offset != null) { - $result.offset = offset; - } - if (length != null) { - $result.length = length; - } - if (replacement != null) { - $result.replacement = replacement; - } - return $result; - } - SourceEdit._() : super(); - factory SourceEdit.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory SourceEdit.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'SourceEdit', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..a<$core.int>(1, _omitFieldNames ? '' : 'offset', $pb.PbFieldType.O3) - ..a<$core.int>(2, _omitFieldNames ? '' : 'length', $pb.PbFieldType.O3) - ..aOS(3, _omitFieldNames ? '' : 'replacement') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - SourceEdit clone() => SourceEdit()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - SourceEdit copyWith(void Function(SourceEdit) updates) => - super.copyWith((message) => updates(message as SourceEdit)) as SourceEdit; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static SourceEdit create() => SourceEdit._(); - SourceEdit createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static SourceEdit getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static SourceEdit? _defaultInstance; - - @$pb.TagNumber(1) - $core.int get offset => $_getIZ(0); - @$pb.TagNumber(1) - set offset($core.int v) { - $_setSignedInt32(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasOffset() => $_has(0); - @$pb.TagNumber(1) - void clearOffset() => clearField(1); - - @$pb.TagNumber(2) - $core.int get length => $_getIZ(1); - @$pb.TagNumber(2) - set length($core.int v) { - $_setSignedInt32(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasLength() => $_has(1); - @$pb.TagNumber(2) - void clearLength() => clearField(2); - - @$pb.TagNumber(3) - $core.String get replacement => $_getSZ(2); - @$pb.TagNumber(3) - set replacement($core.String v) { - $_setString(2, v); - } - - @$pb.TagNumber(3) - $core.bool hasReplacement() => $_has(2); - @$pb.TagNumber(3) - void clearReplacement() => clearField(3); -} - -class LinkedEditGroup extends $pb.GeneratedMessage { - factory LinkedEditGroup({ - $core.Iterable<$core.int>? positions, - $core.int? length, - $core.Iterable? suggestions, - }) { - final $result = create(); - if (positions != null) { - $result.positions.addAll(positions); - } - if (length != null) { - $result.length = length; - } - if (suggestions != null) { - $result.suggestions.addAll(suggestions); - } - return $result; - } - LinkedEditGroup._() : super(); - factory LinkedEditGroup.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory LinkedEditGroup.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'LinkedEditGroup', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..p<$core.int>(1, _omitFieldNames ? '' : 'positions', $pb.PbFieldType.K3) - ..a<$core.int>(2, _omitFieldNames ? '' : 'length', $pb.PbFieldType.O3) - ..pc( - 3, _omitFieldNames ? '' : 'suggestions', $pb.PbFieldType.PM, - subBuilder: LinkedEditSuggestion.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - LinkedEditGroup clone() => LinkedEditGroup()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - LinkedEditGroup copyWith(void Function(LinkedEditGroup) updates) => - super.copyWith((message) => updates(message as LinkedEditGroup)) - as LinkedEditGroup; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static LinkedEditGroup create() => LinkedEditGroup._(); - LinkedEditGroup createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static LinkedEditGroup getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static LinkedEditGroup? _defaultInstance; - - /// The positions of the regions that should be edited simultaneously. - @$pb.TagNumber(1) - $core.List<$core.int> get positions => $_getList(0); - - /// The length of the regions that should be edited simultaneously. - @$pb.TagNumber(2) - $core.int get length => $_getIZ(1); - @$pb.TagNumber(2) - set length($core.int v) { - $_setSignedInt32(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasLength() => $_has(1); - @$pb.TagNumber(2) - void clearLength() => clearField(2); - - /// Pre-computed suggestions for what every region might want to be changed to. - @$pb.TagNumber(3) - $core.List get suggestions => $_getList(2); -} - -class LinkedEditSuggestion extends $pb.GeneratedMessage { - factory LinkedEditSuggestion({ - $core.String? value, - $core.String? kind, - }) { - final $result = create(); - if (value != null) { - $result.value = value; - } - if (kind != null) { - $result.kind = kind; - } - return $result; - } - LinkedEditSuggestion._() : super(); - factory LinkedEditSuggestion.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory LinkedEditSuggestion.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'LinkedEditSuggestion', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'value') - ..aOS(2, _omitFieldNames ? '' : 'kind') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - LinkedEditSuggestion clone() => - LinkedEditSuggestion()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - LinkedEditSuggestion copyWith(void Function(LinkedEditSuggestion) updates) => - super.copyWith((message) => updates(message as LinkedEditSuggestion)) - as LinkedEditSuggestion; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static LinkedEditSuggestion create() => LinkedEditSuggestion._(); - LinkedEditSuggestion createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static LinkedEditSuggestion getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static LinkedEditSuggestion? _defaultInstance; - - /// The value that could be used to replace all of the linked edit regions. - @$pb.TagNumber(1) - $core.String get value => $_getSZ(0); - @$pb.TagNumber(1) - set value($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasValue() => $_has(0); - @$pb.TagNumber(1) - void clearValue() => clearField(1); - - /// The kind of value being proposed. - @$pb.TagNumber(2) - $core.String get kind => $_getSZ(1); - @$pb.TagNumber(2) - set kind($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasKind() => $_has(1); - @$pb.TagNumber(2) - void clearKind() => clearField(2); -} - -/// Represents a reformatting of the code. -class FormatResponse extends $pb.GeneratedMessage { - factory FormatResponse({ - $core.String? newString, - $core.int? offset, - ErrorMessage? error, - }) { - final $result = create(); - if (newString != null) { - $result.newString = newString; - } - if (offset != null) { - $result.offset = offset; - } - if (error != null) { - $result.error = error; - } - return $result; - } - FormatResponse._() : super(); - factory FormatResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory FormatResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'FormatResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'newString', protoName: 'newString') - ..a<$core.int>(2, _omitFieldNames ? '' : 'offset', $pb.PbFieldType.O3) - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - FormatResponse clone() => FormatResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - FormatResponse copyWith(void Function(FormatResponse) updates) => - super.copyWith((message) => updates(message as FormatResponse)) - as FormatResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static FormatResponse create() => FormatResponse._(); - FormatResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static FormatResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static FormatResponse? _defaultInstance; - - /// The formatted source code. - @$pb.TagNumber(1) - $core.String get newString => $_getSZ(0); - @$pb.TagNumber(1) - set newString($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasNewString() => $_has(0); - @$pb.TagNumber(1) - void clearNewString() => clearField(1); - - /// The (optional) new offset of the cursor; can be `null`. - @$pb.TagNumber(2) - $core.int get offset => $_getIZ(1); - @$pb.TagNumber(2) - set offset($core.int v) { - $_setSignedInt32(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasOffset() => $_has(1); - @$pb.TagNumber(2) - void clearOffset() => clearField(2); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(2); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(2); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(2); -} - -/// The response from the `/assists` service call. -class AssistsResponse extends $pb.GeneratedMessage { - factory AssistsResponse({ - $core.Iterable? assists, - ErrorMessage? error, - }) { - final $result = create(); - if (assists != null) { - $result.assists.addAll(assists); - } - if (error != null) { - $result.error = error; - } - return $result; - } - AssistsResponse._() : super(); - factory AssistsResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory AssistsResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'AssistsResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..pc(1, _omitFieldNames ? '' : 'assists', $pb.PbFieldType.PM, - subBuilder: CandidateFix.create) - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - AssistsResponse clone() => AssistsResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - AssistsResponse copyWith(void Function(AssistsResponse) updates) => - super.copyWith((message) => updates(message as AssistsResponse)) - as AssistsResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static AssistsResponse create() => AssistsResponse._(); - AssistsResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static AssistsResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static AssistsResponse? _defaultInstance; - - @$pb.TagNumber(1) - $core.List get assists => $_getList(0); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(1); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(1); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(1); -} - -/// The response from the `/version` service call. -class VersionResponse extends $pb.GeneratedMessage { - factory VersionResponse({ - $core.String? sdkVersion, - $core.String? sdkVersionFull, - @$core.Deprecated('This field is deprecated.') $core.String? runtimeVersion, - @$core.Deprecated('This field is deprecated.') - $core.String? appEngineVersion, - @$core.Deprecated('This field is deprecated.') - $core.String? servicesVersion, - $core.String? flutterVersion, - @$core.Deprecated('This field is deprecated.') - $core.String? flutterDartVersion, - @$core.Deprecated('This field is deprecated.') - $core.String? flutterDartVersionFull, - @$core.Deprecated('This field is deprecated.') - $core.Map<$core.String, $core.String>? packageVersions, - $core.Iterable? packageInfo, - $core.Iterable<$core.String>? experiment, - $core.String? flutterEngineSha, - ErrorMessage? error, - }) { - final $result = create(); - if (sdkVersion != null) { - $result.sdkVersion = sdkVersion; - } - if (sdkVersionFull != null) { - $result.sdkVersionFull = sdkVersionFull; - } - if (runtimeVersion != null) { - // ignore: deprecated_member_use_from_same_package - $result.runtimeVersion = runtimeVersion; - } - if (appEngineVersion != null) { - // ignore: deprecated_member_use_from_same_package - $result.appEngineVersion = appEngineVersion; - } - if (servicesVersion != null) { - // ignore: deprecated_member_use_from_same_package - $result.servicesVersion = servicesVersion; - } - if (flutterVersion != null) { - $result.flutterVersion = flutterVersion; - } - if (flutterDartVersion != null) { - // ignore: deprecated_member_use_from_same_package - $result.flutterDartVersion = flutterDartVersion; - } - if (flutterDartVersionFull != null) { - // ignore: deprecated_member_use_from_same_package - $result.flutterDartVersionFull = flutterDartVersionFull; - } - if (packageVersions != null) { - // ignore: deprecated_member_use_from_same_package - $result.packageVersions.addAll(packageVersions); - } - if (packageInfo != null) { - $result.packageInfo.addAll(packageInfo); - } - if (experiment != null) { - $result.experiment.addAll(experiment); - } - if (flutterEngineSha != null) { - $result.flutterEngineSha = flutterEngineSha; - } - if (error != null) { - $result.error = error; - } - return $result; - } - VersionResponse._() : super(); - factory VersionResponse.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory VersionResponse.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'VersionResponse', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'sdkVersion', protoName: 'sdkVersion') - ..aOS(2, _omitFieldNames ? '' : 'sdkVersionFull', - protoName: 'sdkVersionFull') - ..aOS(3, _omitFieldNames ? '' : 'runtimeVersion', - protoName: 'runtimeVersion') - ..aOS(4, _omitFieldNames ? '' : 'appEngineVersion', - protoName: 'appEngineVersion') - ..aOS(5, _omitFieldNames ? '' : 'servicesVersion', - protoName: 'servicesVersion') - ..aOS(6, _omitFieldNames ? '' : 'flutterVersion', - protoName: 'flutterVersion') - ..aOS(7, _omitFieldNames ? '' : 'flutterDartVersion', - protoName: 'flutterDartVersion') - ..aOS(8, _omitFieldNames ? '' : 'flutterDartVersionFull', - protoName: 'flutterDartVersionFull') - ..m<$core.String, $core.String>(9, _omitFieldNames ? '' : 'packageVersions', - protoName: 'packageVersions', - entryClassName: 'VersionResponse.PackageVersionsEntry', - keyFieldType: $pb.PbFieldType.OS, - valueFieldType: $pb.PbFieldType.OS, - packageName: const $pb.PackageName('dart_services.api')) - ..pc( - 10, _omitFieldNames ? '' : 'packageInfo', $pb.PbFieldType.PM, - protoName: 'packageInfo', subBuilder: PackageInfo.create) - ..pPS(11, _omitFieldNames ? '' : 'experiment') - ..aOS(12, _omitFieldNames ? '' : 'flutterEngineSha', - protoName: 'flutterEngineSha') - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - VersionResponse clone() => VersionResponse()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - VersionResponse copyWith(void Function(VersionResponse) updates) => - super.copyWith((message) => updates(message as VersionResponse)) - as VersionResponse; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static VersionResponse create() => VersionResponse._(); - VersionResponse createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static VersionResponse getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static VersionResponse? _defaultInstance; - - /// The Dart SDK version. - @$pb.TagNumber(1) - $core.String get sdkVersion => $_getSZ(0); - @$pb.TagNumber(1) - set sdkVersion($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasSdkVersion() => $_has(0); - @$pb.TagNumber(1) - void clearSdkVersion() => clearField(1); - - /// The full string of the Dart SDK version, including any channel name. - /// - /// E.g., `3.1.0-262.2.beta` vs `3.1.0`. - @$pb.TagNumber(2) - $core.String get sdkVersionFull => $_getSZ(1); - @$pb.TagNumber(2) - set sdkVersionFull($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasSdkVersionFull() => $_has(1); - @$pb.TagNumber(2) - void clearSdkVersionFull() => clearField(2); - - /// Removed. - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(3) - $core.String get runtimeVersion => $_getSZ(2); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(3) - set runtimeVersion($core.String v) { - $_setString(2, v); - } - - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(3) - $core.bool hasRuntimeVersion() => $_has(2); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(3) - void clearRuntimeVersion() => clearField(3); - - /// Removed. - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(4) - $core.String get appEngineVersion => $_getSZ(3); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(4) - set appEngineVersion($core.String v) { - $_setString(3, v); - } - - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(4) - $core.bool hasAppEngineVersion() => $_has(3); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(4) - void clearAppEngineVersion() => clearField(4); - - /// Removed. - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(5) - $core.String get servicesVersion => $_getSZ(4); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(5) - set servicesVersion($core.String v) { - $_setString(4, v); - } - - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(5) - $core.bool hasServicesVersion() => $_has(4); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(5) - void clearServicesVersion() => clearField(5); - - /// The Flutter SDK version. - @$pb.TagNumber(6) - $core.String get flutterVersion => $_getSZ(5); - @$pb.TagNumber(6) - set flutterVersion($core.String v) { - $_setString(5, v); - } - - @$pb.TagNumber(6) - $core.bool hasFlutterVersion() => $_has(5); - @$pb.TagNumber(6) - void clearFlutterVersion() => clearField(6); - - /// Removed. - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(7) - $core.String get flutterDartVersion => $_getSZ(6); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(7) - set flutterDartVersion($core.String v) { - $_setString(6, v); - } - - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(7) - $core.bool hasFlutterDartVersion() => $_has(6); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(7) - void clearFlutterDartVersion() => clearField(7); - - /// Removed. - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(8) - $core.String get flutterDartVersionFull => $_getSZ(7); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(8) - set flutterDartVersionFull($core.String v) { - $_setString(7, v); - } - - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(8) - $core.bool hasFlutterDartVersionFull() => $_has(7); - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(8) - void clearFlutterDartVersionFull() => clearField(8); - - /// Removed. - @$core.Deprecated('This field is deprecated.') - @$pb.TagNumber(9) - $core.Map<$core.String, $core.String> get packageVersions => $_getMap(8); - - /// Package information; each package found in `pubspec.lock` is included. - @$pb.TagNumber(10) - $core.List get packageInfo => $_getList(9); - - /// Experiments that this server is running. - @$pb.TagNumber(11) - $core.List<$core.String> get experiment => $_getList(10); - - /// The Flutter engine SHA, located in bin/internal/engine.version. - @$pb.TagNumber(12) - $core.String get flutterEngineSha => $_getSZ(11); - @$pb.TagNumber(12) - set flutterEngineSha($core.String v) { - $_setString(11, v); - } - - @$pb.TagNumber(12) - $core.bool hasFlutterEngineSha() => $_has(11); - @$pb.TagNumber(12) - void clearFlutterEngineSha() => clearField(12); - - /// Make this response compatible with BadRequest - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(12); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(12); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(12); -} - -class PackageInfo extends $pb.GeneratedMessage { - factory PackageInfo({ - $core.String? name, - $core.String? version, - $core.bool? supported, - }) { - final $result = create(); - if (name != null) { - $result.name = name; - } - if (version != null) { - $result.version = version; - } - if (supported != null) { - $result.supported = supported; - } - return $result; - } - PackageInfo._() : super(); - factory PackageInfo.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory PackageInfo.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'PackageInfo', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'name') - ..aOS(2, _omitFieldNames ? '' : 'version') - ..aOB(3, _omitFieldNames ? '' : 'supported') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - PackageInfo clone() => PackageInfo()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - PackageInfo copyWith(void Function(PackageInfo) updates) => - super.copyWith((message) => updates(message as PackageInfo)) - as PackageInfo; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static PackageInfo create() => PackageInfo._(); - PackageInfo createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static PackageInfo getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static PackageInfo? _defaultInstance; - - /// The name of this package. - @$pb.TagNumber(1) - $core.String get name => $_getSZ(0); - @$pb.TagNumber(1) - set name($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasName() => $_has(0); - @$pb.TagNumber(1) - void clearName() => clearField(1); - - /// The selected version of this package. - @$pb.TagNumber(2) - $core.String get version => $_getSZ(1); - @$pb.TagNumber(2) - set version($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasVersion() => $_has(1); - @$pb.TagNumber(2) - void clearVersion() => clearField(2); - - /// Whether this package is supported as a directly importable package, - /// or simply available as a transitive dependency of a supported package. - @$pb.TagNumber(3) - $core.bool get supported => $_getBF(2); - @$pb.TagNumber(3) - set supported($core.bool v) { - $_setBool(2, v); - } - - @$pb.TagNumber(3) - $core.bool hasSupported() => $_has(2); - @$pb.TagNumber(3) - void clearSupported() => clearField(3); -} - -/// Response from the server when errors are thrown internally -class BadRequest extends $pb.GeneratedMessage { - factory BadRequest({ - ErrorMessage? error, - }) { - final $result = create(); - if (error != null) { - $result.error = error; - } - return $result; - } - BadRequest._() : super(); - factory BadRequest.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory BadRequest.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'BadRequest', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOM(99, _omitFieldNames ? '' : 'error', - subBuilder: ErrorMessage.create) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - BadRequest clone() => BadRequest()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - BadRequest copyWith(void Function(BadRequest) updates) => - super.copyWith((message) => updates(message as BadRequest)) as BadRequest; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static BadRequest create() => BadRequest._(); - BadRequest createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static BadRequest getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static BadRequest? _defaultInstance; - - @$pb.TagNumber(99) - ErrorMessage get error => $_getN(0); - @$pb.TagNumber(99) - set error(ErrorMessage v) { - setField(99, v); - } - - @$pb.TagNumber(99) - $core.bool hasError() => $_has(0); - @$pb.TagNumber(99) - void clearError() => clearField(99); - @$pb.TagNumber(99) - ErrorMessage ensureError() => $_ensure(0); -} - -/// Individual error messages. -class ErrorMessage extends $pb.GeneratedMessage { - factory ErrorMessage({ - $core.String? message, - }) { - final $result = create(); - if (message != null) { - $result.message = message; - } - return $result; - } - ErrorMessage._() : super(); - factory ErrorMessage.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory ErrorMessage.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - _omitMessageNames ? '' : 'ErrorMessage', - package: - const $pb.PackageName(_omitMessageNames ? '' : 'dart_services.api'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'message') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - ErrorMessage clone() => ErrorMessage()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - ErrorMessage copyWith(void Function(ErrorMessage) updates) => - super.copyWith((message) => updates(message as ErrorMessage)) - as ErrorMessage; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static ErrorMessage create() => ErrorMessage._(); - ErrorMessage createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static ErrorMessage getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static ErrorMessage? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get message => $_getSZ(0); - @$pb.TagNumber(1) - set message($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasMessage() => $_has(0); - @$pb.TagNumber(1) - void clearMessage() => clearField(1); -} - -const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const _omitMessageNames = - $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/pkgs/dart_services/lib/src/protos/dart_services.pbenum.dart b/pkgs/dart_services/lib/src/protos/dart_services.pbenum.dart deleted file mode 100644 index 75e711a69..000000000 --- a/pkgs/dart_services/lib/src/protos/dart_services.pbenum.dart +++ /dev/null @@ -1,10 +0,0 @@ -// -// Generated code. Do not modify. -// source: protos/dart_services.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import diff --git a/pkgs/dart_services/lib/src/protos/dart_services.pbjson.dart b/pkgs/dart_services/lib/src/protos/dart_services.pbjson.dart deleted file mode 100644 index 73e4ce511..000000000 --- a/pkgs/dart_services/lib/src/protos/dart_services.pbjson.dart +++ /dev/null @@ -1,802 +0,0 @@ -// -// Generated code. Do not modify. -// source: protos/dart_services.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -import 'dart:convert' as $convert; -import 'dart:core' as $core; -import 'dart:typed_data' as $typed_data; - -@$core.Deprecated('Use compileRequestDescriptor instead') -const CompileRequest$json = { - '1': 'CompileRequest', - '2': [ - {'1': 'source', '3': 1, '4': 1, '5': 9, '10': 'source'}, - {'1': 'returnSourceMap', '3': 2, '4': 1, '5': 8, '10': 'returnSourceMap'}, - ], -}; - -/// Descriptor for `CompileRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List compileRequestDescriptor = $convert.base64Decode( - 'Cg5Db21waWxlUmVxdWVzdBIWCgZzb3VyY2UYASABKAlSBnNvdXJjZRIoCg9yZXR1cm5Tb3VyY2' - 'VNYXAYAiABKAhSD3JldHVyblNvdXJjZU1hcA=='); - -@$core.Deprecated('Use compileFilesRequestDescriptor instead') -const CompileFilesRequest$json = { - '1': 'CompileFilesRequest', - '2': [ - { - '1': 'files', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.CompileFilesRequest.FilesEntry', - '10': 'files' - }, - {'1': 'returnSourceMap', '3': 2, '4': 1, '5': 8, '10': 'returnSourceMap'}, - ], - '3': [CompileFilesRequest_FilesEntry$json], -}; - -@$core.Deprecated('Use compileFilesRequestDescriptor instead') -const CompileFilesRequest_FilesEntry$json = { - '1': 'FilesEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, -}; - -/// Descriptor for `CompileFilesRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List compileFilesRequestDescriptor = $convert.base64Decode( - 'ChNDb21waWxlRmlsZXNSZXF1ZXN0EkcKBWZpbGVzGAEgAygLMjEuZGFydF9zZXJ2aWNlcy5hcG' - 'kuQ29tcGlsZUZpbGVzUmVxdWVzdC5GaWxlc0VudHJ5UgVmaWxlcxIoCg9yZXR1cm5Tb3VyY2VN' - 'YXAYAiABKAhSD3JldHVyblNvdXJjZU1hcBo4CgpGaWxlc0VudHJ5EhAKA2tleRgBIAEoCVIDa2' - 'V5EhQKBXZhbHVlGAIgASgJUgV2YWx1ZToCOAE='); - -@$core.Deprecated('Use compileDDCRequestDescriptor instead') -const CompileDDCRequest$json = { - '1': 'CompileDDCRequest', - '2': [ - {'1': 'source', '3': 1, '4': 1, '5': 9, '10': 'source'}, - ], -}; - -/// Descriptor for `CompileDDCRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List compileDDCRequestDescriptor = $convert.base64Decode( - 'ChFDb21waWxlRERDUmVxdWVzdBIWCgZzb3VyY2UYASABKAlSBnNvdXJjZQ=='); - -@$core.Deprecated('Use compileFilesDDCRequestDescriptor instead') -const CompileFilesDDCRequest$json = { - '1': 'CompileFilesDDCRequest', - '2': [ - { - '1': 'files', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.CompileFilesDDCRequest.FilesEntry', - '10': 'files' - }, - ], - '3': [CompileFilesDDCRequest_FilesEntry$json], -}; - -@$core.Deprecated('Use compileFilesDDCRequestDescriptor instead') -const CompileFilesDDCRequest_FilesEntry$json = { - '1': 'FilesEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, -}; - -/// Descriptor for `CompileFilesDDCRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List compileFilesDDCRequestDescriptor = $convert.base64Decode( - 'ChZDb21waWxlRmlsZXNERENSZXF1ZXN0EkoKBWZpbGVzGAEgAygLMjQuZGFydF9zZXJ2aWNlcy' - '5hcGkuQ29tcGlsZUZpbGVzRERDUmVxdWVzdC5GaWxlc0VudHJ5UgVmaWxlcxo4CgpGaWxlc0Vu' - 'dHJ5EhAKA2tleRgBIAEoCVIDa2V5EhQKBXZhbHVlGAIgASgJUgV2YWx1ZToCOAE='); - -@$core.Deprecated('Use flutterBuildResponseDescriptor instead') -const FlutterBuildResponse$json = { - '1': 'FlutterBuildResponse', - '2': [ - { - '1': 'artifacts', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.FlutterBuildResponse.ArtifactsEntry', - '10': 'artifacts' - }, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], - '3': [FlutterBuildResponse_ArtifactsEntry$json], -}; - -@$core.Deprecated('Use flutterBuildResponseDescriptor instead') -const FlutterBuildResponse_ArtifactsEntry$json = { - '1': 'ArtifactsEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, -}; - -/// Descriptor for `FlutterBuildResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List flutterBuildResponseDescriptor = $convert.base64Decode( - 'ChRGbHV0dGVyQnVpbGRSZXNwb25zZRJUCglhcnRpZmFjdHMYASADKAsyNi5kYXJ0X3NlcnZpY2' - 'VzLmFwaS5GbHV0dGVyQnVpbGRSZXNwb25zZS5BcnRpZmFjdHNFbnRyeVIJYXJ0aWZhY3RzEjUK' - 'BWVycm9yGGMgASgLMh8uZGFydF9zZXJ2aWNlcy5hcGkuRXJyb3JNZXNzYWdlUgVlcnJvcho8Cg' - '5BcnRpZmFjdHNFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIAEoCVIFdmFsdWU6' - 'AjgB'); - -@$core.Deprecated('Use sourceRequestDescriptor instead') -const SourceRequest$json = { - '1': 'SourceRequest', - '2': [ - {'1': 'source', '3': 1, '4': 1, '5': 9, '10': 'source'}, - {'1': 'offset', '3': 2, '4': 1, '5': 5, '10': 'offset'}, - ], -}; - -/// Descriptor for `SourceRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List sourceRequestDescriptor = $convert.base64Decode( - 'Cg1Tb3VyY2VSZXF1ZXN0EhYKBnNvdXJjZRgBIAEoCVIGc291cmNlEhYKBm9mZnNldBgCIAEoBV' - 'IGb2Zmc2V0'); - -@$core.Deprecated('Use sourceFilesRequestDescriptor instead') -const SourceFilesRequest$json = { - '1': 'SourceFilesRequest', - '2': [ - { - '1': 'files', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.SourceFilesRequest.FilesEntry', - '10': 'files' - }, - {'1': 'activeSourceName', '3': 2, '4': 1, '5': 9, '10': 'activeSourceName'}, - {'1': 'offset', '3': 3, '4': 1, '5': 5, '10': 'offset'}, - ], - '3': [SourceFilesRequest_FilesEntry$json], -}; - -@$core.Deprecated('Use sourceFilesRequestDescriptor instead') -const SourceFilesRequest_FilesEntry$json = { - '1': 'FilesEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, -}; - -/// Descriptor for `SourceFilesRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List sourceFilesRequestDescriptor = $convert.base64Decode( - 'ChJTb3VyY2VGaWxlc1JlcXVlc3QSRgoFZmlsZXMYASADKAsyMC5kYXJ0X3NlcnZpY2VzLmFwaS' - '5Tb3VyY2VGaWxlc1JlcXVlc3QuRmlsZXNFbnRyeVIFZmlsZXMSKgoQYWN0aXZlU291cmNlTmFt' - 'ZRgCIAEoCVIQYWN0aXZlU291cmNlTmFtZRIWCgZvZmZzZXQYAyABKAVSBm9mZnNldBo4CgpGaW' - 'xlc0VudHJ5EhAKA2tleRgBIAEoCVIDa2V5EhQKBXZhbHVlGAIgASgJUgV2YWx1ZToCOAE='); - -@$core.Deprecated('Use analysisResultsDescriptor instead') -const AnalysisResults$json = { - '1': 'AnalysisResults', - '2': [ - { - '1': 'issues', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.AnalysisIssue', - '10': 'issues' - }, - {'1': 'packageImports', '3': 2, '4': 3, '5': 9, '10': 'packageImports'}, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], -}; - -/// Descriptor for `AnalysisResults`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List analysisResultsDescriptor = $convert.base64Decode( - 'Cg9BbmFseXNpc1Jlc3VsdHMSOAoGaXNzdWVzGAEgAygLMiAuZGFydF9zZXJ2aWNlcy5hcGkuQW' - '5hbHlzaXNJc3N1ZVIGaXNzdWVzEiYKDnBhY2thZ2VJbXBvcnRzGAIgAygJUg5wYWNrYWdlSW1w' - 'b3J0cxI1CgVlcnJvchhjIAEoCzIfLmRhcnRfc2VydmljZXMuYXBpLkVycm9yTWVzc2FnZVIFZX' - 'Jyb3I='); - -@$core.Deprecated('Use analysisIssueDescriptor instead') -const AnalysisIssue$json = { - '1': 'AnalysisIssue', - '2': [ - {'1': 'kind', '3': 1, '4': 1, '5': 9, '10': 'kind'}, - {'1': 'line', '3': 2, '4': 1, '5': 5, '10': 'line'}, - {'1': 'message', '3': 3, '4': 1, '5': 9, '10': 'message'}, - {'1': 'sourceName', '3': 4, '4': 1, '5': 9, '10': 'sourceName'}, - {'1': 'hasFixes', '3': 5, '4': 1, '5': 8, '10': 'hasFixes'}, - {'1': 'charStart', '3': 6, '4': 1, '5': 5, '10': 'charStart'}, - {'1': 'charLength', '3': 7, '4': 1, '5': 5, '10': 'charLength'}, - {'1': 'url', '3': 8, '4': 1, '5': 9, '10': 'url'}, - { - '1': 'diagnosticMessages', - '3': 9, - '4': 3, - '5': 11, - '6': '.dart_services.api.DiagnosticMessage', - '10': 'diagnosticMessages' - }, - {'1': 'correction', '3': 10, '4': 1, '5': 9, '10': 'correction'}, - {'1': 'column', '3': 11, '4': 1, '5': 5, '10': 'column'}, - {'1': 'code', '3': 12, '4': 1, '5': 9, '10': 'code'}, - ], -}; - -/// Descriptor for `AnalysisIssue`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List analysisIssueDescriptor = $convert.base64Decode( - 'Cg1BbmFseXNpc0lzc3VlEhIKBGtpbmQYASABKAlSBGtpbmQSEgoEbGluZRgCIAEoBVIEbGluZR' - 'IYCgdtZXNzYWdlGAMgASgJUgdtZXNzYWdlEh4KCnNvdXJjZU5hbWUYBCABKAlSCnNvdXJjZU5h' - 'bWUSGgoIaGFzRml4ZXMYBSABKAhSCGhhc0ZpeGVzEhwKCWNoYXJTdGFydBgGIAEoBVIJY2hhcl' - 'N0YXJ0Eh4KCmNoYXJMZW5ndGgYByABKAVSCmNoYXJMZW5ndGgSEAoDdXJsGAggASgJUgN1cmwS' - 'VAoSZGlhZ25vc3RpY01lc3NhZ2VzGAkgAygLMiQuZGFydF9zZXJ2aWNlcy5hcGkuRGlhZ25vc3' - 'RpY01lc3NhZ2VSEmRpYWdub3N0aWNNZXNzYWdlcxIeCgpjb3JyZWN0aW9uGAogASgJUgpjb3Jy' - 'ZWN0aW9uEhYKBmNvbHVtbhgLIAEoBVIGY29sdW1uEhIKBGNvZGUYDCABKAlSBGNvZGU='); - -@$core.Deprecated('Use diagnosticMessageDescriptor instead') -const DiagnosticMessage$json = { - '1': 'DiagnosticMessage', - '2': [ - {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'}, - {'1': 'line', '3': 2, '4': 1, '5': 5, '10': 'line'}, - {'1': 'charStart', '3': 3, '4': 1, '5': 5, '10': 'charStart'}, - {'1': 'charLength', '3': 4, '4': 1, '5': 5, '10': 'charLength'}, - {'1': 'column', '3': 5, '4': 1, '5': 5, '10': 'column'}, - ], -}; - -/// Descriptor for `DiagnosticMessage`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List diagnosticMessageDescriptor = $convert.base64Decode( - 'ChFEaWFnbm9zdGljTWVzc2FnZRIYCgdtZXNzYWdlGAEgASgJUgdtZXNzYWdlEhIKBGxpbmUYAi' - 'ABKAVSBGxpbmUSHAoJY2hhclN0YXJ0GAMgASgFUgljaGFyU3RhcnQSHgoKY2hhckxlbmd0aBgE' - 'IAEoBVIKY2hhckxlbmd0aBIWCgZjb2x1bW4YBSABKAVSBmNvbHVtbg=='); - -@$core.Deprecated('Use versionRequestDescriptor instead') -const VersionRequest$json = { - '1': 'VersionRequest', -}; - -/// Descriptor for `VersionRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List versionRequestDescriptor = - $convert.base64Decode('Cg5WZXJzaW9uUmVxdWVzdA=='); - -@$core.Deprecated('Use compileResponseDescriptor instead') -const CompileResponse$json = { - '1': 'CompileResponse', - '2': [ - {'1': 'result', '3': 1, '4': 1, '5': 9, '10': 'result'}, - {'1': 'sourceMap', '3': 2, '4': 1, '5': 9, '10': 'sourceMap'}, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], -}; - -/// Descriptor for `CompileResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List compileResponseDescriptor = $convert.base64Decode( - 'Cg9Db21waWxlUmVzcG9uc2USFgoGcmVzdWx0GAEgASgJUgZyZXN1bHQSHAoJc291cmNlTWFwGA' - 'IgASgJUglzb3VyY2VNYXASNQoFZXJyb3IYYyABKAsyHy5kYXJ0X3NlcnZpY2VzLmFwaS5FcnJv' - 'ck1lc3NhZ2VSBWVycm9y'); - -@$core.Deprecated('Use compileDDCResponseDescriptor instead') -const CompileDDCResponse$json = { - '1': 'CompileDDCResponse', - '2': [ - {'1': 'result', '3': 1, '4': 1, '5': 9, '10': 'result'}, - {'1': 'modulesBaseUrl', '3': 2, '4': 1, '5': 9, '10': 'modulesBaseUrl'}, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], -}; - -/// Descriptor for `CompileDDCResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List compileDDCResponseDescriptor = $convert.base64Decode( - 'ChJDb21waWxlRERDUmVzcG9uc2USFgoGcmVzdWx0GAEgASgJUgZyZXN1bHQSJgoObW9kdWxlc0' - 'Jhc2VVcmwYAiABKAlSDm1vZHVsZXNCYXNlVXJsEjUKBWVycm9yGGMgASgLMh8uZGFydF9zZXJ2' - 'aWNlcy5hcGkuRXJyb3JNZXNzYWdlUgVlcnJvcg=='); - -@$core.Deprecated('Use documentResponseDescriptor instead') -const DocumentResponse$json = { - '1': 'DocumentResponse', - '2': [ - { - '1': 'info', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.DocumentResponse.InfoEntry', - '10': 'info' - }, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], - '3': [DocumentResponse_InfoEntry$json], -}; - -@$core.Deprecated('Use documentResponseDescriptor instead') -const DocumentResponse_InfoEntry$json = { - '1': 'InfoEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, -}; - -/// Descriptor for `DocumentResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List documentResponseDescriptor = $convert.base64Decode( - 'ChBEb2N1bWVudFJlc3BvbnNlEkEKBGluZm8YASADKAsyLS5kYXJ0X3NlcnZpY2VzLmFwaS5Eb2' - 'N1bWVudFJlc3BvbnNlLkluZm9FbnRyeVIEaW5mbxI1CgVlcnJvchhjIAEoCzIfLmRhcnRfc2Vy' - 'dmljZXMuYXBpLkVycm9yTWVzc2FnZVIFZXJyb3IaNwoJSW5mb0VudHJ5EhAKA2tleRgBIAEoCV' - 'IDa2V5EhQKBXZhbHVlGAIgASgJUgV2YWx1ZToCOAE='); - -@$core.Deprecated('Use completeResponseDescriptor instead') -const CompleteResponse$json = { - '1': 'CompleteResponse', - '2': [ - { - '1': 'replacementOffset', - '3': 1, - '4': 1, - '5': 5, - '10': 'replacementOffset' - }, - { - '1': 'replacementLength', - '3': 2, - '4': 1, - '5': 5, - '10': 'replacementLength' - }, - { - '1': 'completions', - '3': 3, - '4': 3, - '5': 11, - '6': '.dart_services.api.Completion', - '10': 'completions' - }, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], -}; - -/// Descriptor for `CompleteResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List completeResponseDescriptor = $convert.base64Decode( - 'ChBDb21wbGV0ZVJlc3BvbnNlEiwKEXJlcGxhY2VtZW50T2Zmc2V0GAEgASgFUhFyZXBsYWNlbW' - 'VudE9mZnNldBIsChFyZXBsYWNlbWVudExlbmd0aBgCIAEoBVIRcmVwbGFjZW1lbnRMZW5ndGgS' - 'PwoLY29tcGxldGlvbnMYAyADKAsyHS5kYXJ0X3NlcnZpY2VzLmFwaS5Db21wbGV0aW9uUgtjb2' - '1wbGV0aW9ucxI1CgVlcnJvchhjIAEoCzIfLmRhcnRfc2VydmljZXMuYXBpLkVycm9yTWVzc2Fn' - 'ZVIFZXJyb3I='); - -@$core.Deprecated('Use completionDescriptor instead') -const Completion$json = { - '1': 'Completion', - '2': [ - { - '1': 'completion', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.Completion.CompletionEntry', - '10': 'completion' - }, - ], - '3': [Completion_CompletionEntry$json], -}; - -@$core.Deprecated('Use completionDescriptor instead') -const Completion_CompletionEntry$json = { - '1': 'CompletionEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, -}; - -/// Descriptor for `Completion`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List completionDescriptor = $convert.base64Decode( - 'CgpDb21wbGV0aW9uEk0KCmNvbXBsZXRpb24YASADKAsyLS5kYXJ0X3NlcnZpY2VzLmFwaS5Db2' - '1wbGV0aW9uLkNvbXBsZXRpb25FbnRyeVIKY29tcGxldGlvbho9Cg9Db21wbGV0aW9uRW50cnkS' - 'EAoDa2V5GAEgASgJUgNrZXkSFAoFdmFsdWUYAiABKAlSBXZhbHVlOgI4AQ=='); - -@$core.Deprecated('Use fixesResponseDescriptor instead') -const FixesResponse$json = { - '1': 'FixesResponse', - '2': [ - { - '1': 'fixes', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.ProblemAndFixes', - '10': 'fixes' - }, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], -}; - -/// Descriptor for `FixesResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List fixesResponseDescriptor = $convert.base64Decode( - 'Cg1GaXhlc1Jlc3BvbnNlEjgKBWZpeGVzGAEgAygLMiIuZGFydF9zZXJ2aWNlcy5hcGkuUHJvYm' - 'xlbUFuZEZpeGVzUgVmaXhlcxI1CgVlcnJvchhjIAEoCzIfLmRhcnRfc2VydmljZXMuYXBpLkVy' - 'cm9yTWVzc2FnZVIFZXJyb3I='); - -@$core.Deprecated('Use problemAndFixesDescriptor instead') -const ProblemAndFixes$json = { - '1': 'ProblemAndFixes', - '2': [ - { - '1': 'fixes', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.CandidateFix', - '10': 'fixes' - }, - {'1': 'problemMessage', '3': 2, '4': 1, '5': 9, '10': 'problemMessage'}, - {'1': 'offset', '3': 3, '4': 1, '5': 5, '10': 'offset'}, - {'1': 'length', '3': 4, '4': 1, '5': 5, '10': 'length'}, - ], -}; - -/// Descriptor for `ProblemAndFixes`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List problemAndFixesDescriptor = $convert.base64Decode( - 'Cg9Qcm9ibGVtQW5kRml4ZXMSNQoFZml4ZXMYASADKAsyHy5kYXJ0X3NlcnZpY2VzLmFwaS5DYW' - '5kaWRhdGVGaXhSBWZpeGVzEiYKDnByb2JsZW1NZXNzYWdlGAIgASgJUg5wcm9ibGVtTWVzc2Fn' - 'ZRIWCgZvZmZzZXQYAyABKAVSBm9mZnNldBIWCgZsZW5ndGgYBCABKAVSBmxlbmd0aA=='); - -@$core.Deprecated('Use candidateFixDescriptor instead') -const CandidateFix$json = { - '1': 'CandidateFix', - '2': [ - {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'}, - { - '1': 'edits', - '3': 2, - '4': 3, - '5': 11, - '6': '.dart_services.api.SourceEdit', - '10': 'edits' - }, - {'1': 'selectionOffset', '3': 3, '4': 1, '5': 5, '10': 'selectionOffset'}, - { - '1': 'linkedEditGroups', - '3': 4, - '4': 3, - '5': 11, - '6': '.dart_services.api.LinkedEditGroup', - '10': 'linkedEditGroups' - }, - ], -}; - -/// Descriptor for `CandidateFix`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List candidateFixDescriptor = $convert.base64Decode( - 'CgxDYW5kaWRhdGVGaXgSGAoHbWVzc2FnZRgBIAEoCVIHbWVzc2FnZRIzCgVlZGl0cxgCIAMoCz' - 'IdLmRhcnRfc2VydmljZXMuYXBpLlNvdXJjZUVkaXRSBWVkaXRzEigKD3NlbGVjdGlvbk9mZnNl' - 'dBgDIAEoBVIPc2VsZWN0aW9uT2Zmc2V0Ek4KEGxpbmtlZEVkaXRHcm91cHMYBCADKAsyIi5kYX' - 'J0X3NlcnZpY2VzLmFwaS5MaW5rZWRFZGl0R3JvdXBSEGxpbmtlZEVkaXRHcm91cHM='); - -@$core.Deprecated('Use sourceEditDescriptor instead') -const SourceEdit$json = { - '1': 'SourceEdit', - '2': [ - {'1': 'offset', '3': 1, '4': 1, '5': 5, '10': 'offset'}, - {'1': 'length', '3': 2, '4': 1, '5': 5, '10': 'length'}, - {'1': 'replacement', '3': 3, '4': 1, '5': 9, '10': 'replacement'}, - ], -}; - -/// Descriptor for `SourceEdit`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List sourceEditDescriptor = $convert.base64Decode( - 'CgpTb3VyY2VFZGl0EhYKBm9mZnNldBgBIAEoBVIGb2Zmc2V0EhYKBmxlbmd0aBgCIAEoBVIGbG' - 'VuZ3RoEiAKC3JlcGxhY2VtZW50GAMgASgJUgtyZXBsYWNlbWVudA=='); - -@$core.Deprecated('Use linkedEditGroupDescriptor instead') -const LinkedEditGroup$json = { - '1': 'LinkedEditGroup', - '2': [ - {'1': 'positions', '3': 1, '4': 3, '5': 5, '10': 'positions'}, - {'1': 'length', '3': 2, '4': 1, '5': 5, '10': 'length'}, - { - '1': 'suggestions', - '3': 3, - '4': 3, - '5': 11, - '6': '.dart_services.api.LinkedEditSuggestion', - '10': 'suggestions' - }, - ], -}; - -/// Descriptor for `LinkedEditGroup`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List linkedEditGroupDescriptor = $convert.base64Decode( - 'Cg9MaW5rZWRFZGl0R3JvdXASHAoJcG9zaXRpb25zGAEgAygFUglwb3NpdGlvbnMSFgoGbGVuZ3' - 'RoGAIgASgFUgZsZW5ndGgSSQoLc3VnZ2VzdGlvbnMYAyADKAsyJy5kYXJ0X3NlcnZpY2VzLmFw' - 'aS5MaW5rZWRFZGl0U3VnZ2VzdGlvblILc3VnZ2VzdGlvbnM='); - -@$core.Deprecated('Use linkedEditSuggestionDescriptor instead') -const LinkedEditSuggestion$json = { - '1': 'LinkedEditSuggestion', - '2': [ - {'1': 'value', '3': 1, '4': 1, '5': 9, '10': 'value'}, - {'1': 'kind', '3': 2, '4': 1, '5': 9, '10': 'kind'}, - ], -}; - -/// Descriptor for `LinkedEditSuggestion`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List linkedEditSuggestionDescriptor = $convert.base64Decode( - 'ChRMaW5rZWRFZGl0U3VnZ2VzdGlvbhIUCgV2YWx1ZRgBIAEoCVIFdmFsdWUSEgoEa2luZBgCIA' - 'EoCVIEa2luZA=='); - -@$core.Deprecated('Use formatResponseDescriptor instead') -const FormatResponse$json = { - '1': 'FormatResponse', - '2': [ - {'1': 'newString', '3': 1, '4': 1, '5': 9, '10': 'newString'}, - {'1': 'offset', '3': 2, '4': 1, '5': 5, '10': 'offset'}, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], -}; - -/// Descriptor for `FormatResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List formatResponseDescriptor = $convert.base64Decode( - 'Cg5Gb3JtYXRSZXNwb25zZRIcCgluZXdTdHJpbmcYASABKAlSCW5ld1N0cmluZxIWCgZvZmZzZX' - 'QYAiABKAVSBm9mZnNldBI1CgVlcnJvchhjIAEoCzIfLmRhcnRfc2VydmljZXMuYXBpLkVycm9y' - 'TWVzc2FnZVIFZXJyb3I='); - -@$core.Deprecated('Use assistsResponseDescriptor instead') -const AssistsResponse$json = { - '1': 'AssistsResponse', - '2': [ - { - '1': 'assists', - '3': 1, - '4': 3, - '5': 11, - '6': '.dart_services.api.CandidateFix', - '10': 'assists' - }, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], -}; - -/// Descriptor for `AssistsResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List assistsResponseDescriptor = $convert.base64Decode( - 'Cg9Bc3Npc3RzUmVzcG9uc2USOQoHYXNzaXN0cxgBIAMoCzIfLmRhcnRfc2VydmljZXMuYXBpLk' - 'NhbmRpZGF0ZUZpeFIHYXNzaXN0cxI1CgVlcnJvchhjIAEoCzIfLmRhcnRfc2VydmljZXMuYXBp' - 'LkVycm9yTWVzc2FnZVIFZXJyb3I='); - -@$core.Deprecated('Use versionResponseDescriptor instead') -const VersionResponse$json = { - '1': 'VersionResponse', - '2': [ - {'1': 'sdkVersion', '3': 1, '4': 1, '5': 9, '10': 'sdkVersion'}, - {'1': 'sdkVersionFull', '3': 2, '4': 1, '5': 9, '10': 'sdkVersionFull'}, - { - '1': 'runtimeVersion', - '3': 3, - '4': 1, - '5': 9, - '8': {'3': true}, - '10': 'runtimeVersion', - }, - { - '1': 'appEngineVersion', - '3': 4, - '4': 1, - '5': 9, - '8': {'3': true}, - '10': 'appEngineVersion', - }, - { - '1': 'servicesVersion', - '3': 5, - '4': 1, - '5': 9, - '8': {'3': true}, - '10': 'servicesVersion', - }, - {'1': 'flutterVersion', '3': 6, '4': 1, '5': 9, '10': 'flutterVersion'}, - { - '1': 'flutterDartVersion', - '3': 7, - '4': 1, - '5': 9, - '8': {'3': true}, - '10': 'flutterDartVersion', - }, - { - '1': 'flutterDartVersionFull', - '3': 8, - '4': 1, - '5': 9, - '8': {'3': true}, - '10': 'flutterDartVersionFull', - }, - { - '1': 'packageVersions', - '3': 9, - '4': 3, - '5': 11, - '6': '.dart_services.api.VersionResponse.PackageVersionsEntry', - '8': {'3': true}, - '10': 'packageVersions', - }, - { - '1': 'packageInfo', - '3': 10, - '4': 3, - '5': 11, - '6': '.dart_services.api.PackageInfo', - '10': 'packageInfo' - }, - {'1': 'experiment', '3': 11, '4': 3, '5': 9, '10': 'experiment'}, - { - '1': 'flutterEngineSha', - '3': 12, - '4': 1, - '5': 9, - '10': 'flutterEngineSha' - }, - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], - '3': [VersionResponse_PackageVersionsEntry$json], -}; - -@$core.Deprecated('Use versionResponseDescriptor instead') -const VersionResponse_PackageVersionsEntry$json = { - '1': 'PackageVersionsEntry', - '2': [ - {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, - {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, - ], - '7': {'7': true}, -}; - -/// Descriptor for `VersionResponse`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List versionResponseDescriptor = $convert.base64Decode( - 'Cg9WZXJzaW9uUmVzcG9uc2USHgoKc2RrVmVyc2lvbhgBIAEoCVIKc2RrVmVyc2lvbhImCg5zZG' - 'tWZXJzaW9uRnVsbBgCIAEoCVIOc2RrVmVyc2lvbkZ1bGwSKgoOcnVudGltZVZlcnNpb24YAyAB' - 'KAlCAhgBUg5ydW50aW1lVmVyc2lvbhIuChBhcHBFbmdpbmVWZXJzaW9uGAQgASgJQgIYAVIQYX' - 'BwRW5naW5lVmVyc2lvbhIsCg9zZXJ2aWNlc1ZlcnNpb24YBSABKAlCAhgBUg9zZXJ2aWNlc1Zl' - 'cnNpb24SJgoOZmx1dHRlclZlcnNpb24YBiABKAlSDmZsdXR0ZXJWZXJzaW9uEjIKEmZsdXR0ZX' - 'JEYXJ0VmVyc2lvbhgHIAEoCUICGAFSEmZsdXR0ZXJEYXJ0VmVyc2lvbhI6ChZmbHV0dGVyRGFy' - 'dFZlcnNpb25GdWxsGAggASgJQgIYAVIWZmx1dHRlckRhcnRWZXJzaW9uRnVsbBJlCg9wYWNrYW' - 'dlVmVyc2lvbnMYCSADKAsyNy5kYXJ0X3NlcnZpY2VzLmFwaS5WZXJzaW9uUmVzcG9uc2UuUGFj' - 'a2FnZVZlcnNpb25zRW50cnlCAhgBUg9wYWNrYWdlVmVyc2lvbnMSQAoLcGFja2FnZUluZm8YCi' - 'ADKAsyHi5kYXJ0X3NlcnZpY2VzLmFwaS5QYWNrYWdlSW5mb1ILcGFja2FnZUluZm8SHgoKZXhw' - 'ZXJpbWVudBgLIAMoCVIKZXhwZXJpbWVudBIqChBmbHV0dGVyRW5naW5lU2hhGAwgASgJUhBmbH' - 'V0dGVyRW5naW5lU2hhEjUKBWVycm9yGGMgASgLMh8uZGFydF9zZXJ2aWNlcy5hcGkuRXJyb3JN' - 'ZXNzYWdlUgVlcnJvchpCChRQYWNrYWdlVmVyc2lvbnNFbnRyeRIQCgNrZXkYASABKAlSA2tleR' - 'IUCgV2YWx1ZRgCIAEoCVIFdmFsdWU6AjgB'); - -@$core.Deprecated('Use packageInfoDescriptor instead') -const PackageInfo$json = { - '1': 'PackageInfo', - '2': [ - {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, - {'1': 'version', '3': 2, '4': 1, '5': 9, '10': 'version'}, - {'1': 'supported', '3': 3, '4': 1, '5': 8, '10': 'supported'}, - ], -}; - -/// Descriptor for `PackageInfo`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List packageInfoDescriptor = $convert.base64Decode( - 'CgtQYWNrYWdlSW5mbxISCgRuYW1lGAEgASgJUgRuYW1lEhgKB3ZlcnNpb24YAiABKAlSB3Zlcn' - 'Npb24SHAoJc3VwcG9ydGVkGAMgASgIUglzdXBwb3J0ZWQ='); - -@$core.Deprecated('Use badRequestDescriptor instead') -const BadRequest$json = { - '1': 'BadRequest', - '2': [ - { - '1': 'error', - '3': 99, - '4': 1, - '5': 11, - '6': '.dart_services.api.ErrorMessage', - '10': 'error' - }, - ], -}; - -/// Descriptor for `BadRequest`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List badRequestDescriptor = $convert.base64Decode( - 'CgpCYWRSZXF1ZXN0EjUKBWVycm9yGGMgASgLMh8uZGFydF9zZXJ2aWNlcy5hcGkuRXJyb3JNZX' - 'NzYWdlUgVlcnJvcg=='); - -@$core.Deprecated('Use errorMessageDescriptor instead') -const ErrorMessage$json = { - '1': 'ErrorMessage', - '2': [ - {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'}, - ], -}; - -/// Descriptor for `ErrorMessage`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List errorMessageDescriptor = $convert - .base64Decode('CgxFcnJvck1lc3NhZ2USGAoHbWVzc2FnZRgBIAEoCVIHbWVzc2FnZQ=='); diff --git a/pkgs/dart_services/lib/src/protos/dart_services.pbserver.dart b/pkgs/dart_services/lib/src/protos/dart_services.pbserver.dart deleted file mode 100644 index c9b6a46da..000000000 --- a/pkgs/dart_services/lib/src/protos/dart_services.pbserver.dart +++ /dev/null @@ -1,13 +0,0 @@ -// -// Generated code. Do not modify. -// source: protos/dart_services.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names -// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -export 'dart_services.pb.dart'; diff --git a/pkgs/dart_services/lib/src/pub.dart b/pkgs/dart_services/lib/src/pub.dart index 3cbf7026e..b61fbe8d0 100644 --- a/pkgs/dart_services/lib/src/pub.dart +++ b/pkgs/dart_services/lib/src/pub.dart @@ -9,7 +9,7 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:path/path.dart' as path; import 'package:yaml/yaml.dart'; -import 'project.dart' as project; +import 'project_templates.dart' as project; /// Extract all imports from [dartSource] source code. List getAllImportsFor(String? dartSource) { @@ -19,15 +19,6 @@ List getAllImportsFor(String? dartSource) { return unit.directives.whereType().toList(); } -/// Takes a map {"filename":"sourcecode"..."filenameN":"sourcecodeN"} -/// of source files and extracts the imports from each file's sourcecode and -/// returns an overall list of all imports across all files in the set. -List getAllImportsForFiles(Map files) { - return [ - for (final sourcecode in files.values) ...getAllImportsFor(sourcecode) - ]; -} - /// Flutter packages which do not have version numbers in pubspec.lock. const _flutterPackages = [ 'flutter', @@ -77,13 +68,13 @@ Map packageVersionsFromPubspecLock(String templatePath) { return packageVersions; } -extension ImportIterableExtensions on Iterable { - /// Returns the names of packages that are referenced in this collection. - /// These package names are sanitized defensively. - Iterable filterSafePackages() { - return where((import) => !import.uri.stringValue!.startsWith('package:../')) - .map((import) => Uri.parse(import.uri.stringValue!)) - .where((uri) => uri.scheme == 'package' && uri.pathSegments.isNotEmpty) - .map((uri) => uri.pathSegments.first); - } +/// Returns the names of packages that are referenced in this collection. +/// These package names are sanitized defensively. +List filterSafePackages(List imports) { + return imports + .where((import) => !import.uri.stringValue!.startsWith('package:../')) + .map((import) => Uri.parse(import.uri.stringValue!)) + .where((uri) => uri.scheme == 'package' && uri.pathSegments.isNotEmpty) + .map((uri) => uri.pathSegments.first) + .toList(); } diff --git a/pkgs/dart_services/lib/src/scheduler.dart b/pkgs/dart_services/lib/src/scheduler.dart deleted file mode 100644 index e64b557c2..000000000 --- a/pkgs/dart_services/lib/src/scheduler.dart +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file -// 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'; -import 'dart:collection'; - -class TaskScheduler { - final Queue<_Task> _taskQueue = Queue<_Task>(); - bool _isActive = false; - - int get queueCount => _taskQueue.length; - - Future _performTask(Task task) { - return task.perform().timeout(task.timeoutDuration); - } - - Future schedule(Task task) { - if (!_isActive) { - _isActive = true; - return _performTask(task).whenComplete(_next); - } - - final taskResult = Completer(); - _taskQueue.add(_Task(task, taskResult)); - return taskResult.future; - } - - void _next() { - assert(_isActive); - if (_taskQueue.isEmpty) { - _isActive = false; - return; - } - - final first = _taskQueue.removeFirst(); - first.taskResult.complete(_performTask(first.task).whenComplete(_next)); - } -} - -// Internal unit of scheduling. -class _Task { - final Task task; - final Completer taskResult; - - _Task(this.task, this.taskResult); -} - -// Public working data structure. -abstract class Task { - late Duration timeoutDuration; - Future perform(); -} - -class ClosureTask extends Task { - final Future Function() _closure; - - ClosureTask(this._closure, {required Duration timeoutDuration}) { - this.timeoutDuration = timeoutDuration; - } - - @override - Future perform() { - return _closure(); - } -} diff --git a/pkgs/dart_services/lib/src/sdk.dart b/pkgs/dart_services/lib/src/sdk.dart index 9d0ae9d5e..b17860869 100644 --- a/pkgs/dart_services/lib/src/sdk.dart +++ b/pkgs/dart_services/lib/src/sdk.dart @@ -46,15 +46,15 @@ class Sdk { return const []; } - // When running with `dart run`, the FLUTTER_ROOT environment variable is - // set automatically. String _getSdkPath() { - final env = Platform.environment; - if (!env.containsKey('FLUTTER_ROOT') || env['FLUTTER_ROOT']!.isEmpty) { - throw Exception('No FLUTTER_ROOT variable set'); - } + // /bin/cache/dart-sdk + final dart = Platform.resolvedExecutable; + final dartSdk = path.dirname(path.dirname(dart)); + final flutterSdk = path.dirname(path.dirname(path.dirname(dartSdk))); + + // todo: verify that this is a flutter sdk - return env['FLUTTER_ROOT']!; + return flutterSdk; } String get sdkPath => _sdkPath ??= _getSdkPath(); diff --git a/pkgs/dart_services/lib/src/shared/model.dart b/pkgs/dart_services/lib/src/shared/model.dart index 50b093274..c27d74870 100644 --- a/pkgs/dart_services/lib/src/shared/model.dart +++ b/pkgs/dart_services/lib/src/shared/model.dart @@ -43,6 +43,7 @@ class AnalysisIssue { final String kind; final String message; final Location location; + final String? code; final String? correction; final String? url; final List? contextMessages; @@ -53,6 +54,7 @@ class AnalysisIssue { required this.kind, required this.message, required this.location, + this.code, this.correction, this.url, this.contextMessages, @@ -64,6 +66,15 @@ class AnalysisIssue { Map toJson() => _$AnalysisIssueToJson(this); + int get severity { + return switch (kind) { + 'error' => 3, + 'warning' => 2, + 'info' => 1, + _ => 0, + }; + } + @override String toString() => '[$kind] $message'; } @@ -163,18 +174,6 @@ class FormatResponse { String toString() => 'FormatResponse[source=$source,offset=$offset]'; } -@JsonSerializable() -class FlutterBuildResponse { - final Map artifacts; - - FlutterBuildResponse({required this.artifacts}); - - factory FlutterBuildResponse.fromJson(Map json) => - _$FlutterBuildResponseFromJson(json); - - Map toJson() => _$FlutterBuildResponseToJson(this); -} - @JsonSerializable() class FixesResponse { static final FixesResponse empty = FixesResponse( diff --git a/pkgs/dart_services/lib/src/shared/model.g.dart b/pkgs/dart_services/lib/src/shared/model.g.dart index f670137e0..5e9577936 100644 --- a/pkgs/dart_services/lib/src/shared/model.g.dart +++ b/pkgs/dart_services/lib/src/shared/model.g.dart @@ -39,6 +39,7 @@ AnalysisIssue _$AnalysisIssueFromJson(Map json) => kind: json['kind'] as String, message: json['message'] as String, location: Location.fromJson(json['location'] as Map), + code: json['code'] as String?, correction: json['correction'] as String?, url: json['url'] as String?, contextMessages: (json['contextMessages'] as List?) @@ -52,6 +53,7 @@ Map _$AnalysisIssueToJson(AnalysisIssue instance) => 'kind': instance.kind, 'message': instance.message, 'location': instance.location, + 'code': instance.code, 'correction': instance.correction, 'url': instance.url, 'contextMessages': instance.contextMessages, @@ -128,18 +130,6 @@ Map _$FormatResponseToJson(FormatResponse instance) => 'offset': instance.offset, }; -FlutterBuildResponse _$FlutterBuildResponseFromJson( - Map json) => - FlutterBuildResponse( - artifacts: Map.from(json['artifacts'] as Map), - ); - -Map _$FlutterBuildResponseToJson( - FlutterBuildResponse instance) => - { - 'artifacts': instance.artifacts, - }; - FixesResponse _$FixesResponseFromJson(Map json) => FixesResponse( fixes: (json['fixes'] as List) diff --git a/pkgs/dart_services/lib/src/shared/services.dart b/pkgs/dart_services/lib/src/shared/services.dart index 29dd904cf..ee49d2941 100644 --- a/pkgs/dart_services/lib/src/shared/services.dart +++ b/pkgs/dart_services/lib/src/shared/services.dart @@ -40,11 +40,6 @@ class ServicesClient { Future compileDDC(CompileRequest request) => _requestPost('compileDDC', request.toJson(), CompileDDCResponse.fromJson); - /// Note that this call is experimental and can change at any time. - Future flutterBuild(SourceRequest request) => - _requestPost( - '_flutterBuild', request.toJson(), FlutterBuildResponse.fromJson); - void dispose() => client.close(); Future _requestGet( diff --git a/pkgs/dart_services/lib/src/shelf_cors.dart b/pkgs/dart_services/lib/src/shelf_cors.dart index aa94a1d59..5314525e3 100644 --- a/pkgs/dart_services/lib/src/shelf_cors.dart +++ b/pkgs/dart_services/lib/src/shelf_cors.dart @@ -3,16 +3,16 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:async'; + import 'package:shelf/shelf.dart'; /// Middleware which adds [CORS headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) /// to shelf responses. Also handles preflight (OPTIONS) requests. /// /// By default, allows access from everywhere. -Middleware createCorsHeadersMiddleware( - {Map corsHeaders = const { - 'Access-Control-Allow-Origin': '*' - }}) { +Middleware createCorsHeadersMiddleware({ + Map corsHeaders = const {'Access-Control-Allow-Origin': '*'}, +}) { // Handle preflight (OPTIONS) requests by just adding headers and an empty // response. FutureOr handleOptionsRequest(Request request) { diff --git a/pkgs/dart_services/lib/src/utils.dart b/pkgs/dart_services/lib/src/utils.dart index 27b8ab317..5f147bc6d 100644 --- a/pkgs/dart_services/lib/src/utils.dart +++ b/pkgs/dart_services/lib/src/utils.dart @@ -2,6 +2,8 @@ // 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'; +import 'dart:collection'; import 'dart:io'; import 'package:path/path.dart' as path; @@ -51,9 +53,9 @@ Future runWithLogging( required void Function(String) log, }) async { log([ - 'Running $executable ${arguments.join(' ')}', - if (workingDirectory != null) "from directory: '$workingDirectory'", - if (environment.isNotEmpty) 'with additional environment: $environment', + '${path.basename(executable)} ${arguments.join(' ')}:', + if (workingDirectory != null) 'cwd: $workingDirectory', + if (environment.isNotEmpty) 'env: $environment', ].join('\n ')); final process = await Process.start(executable, arguments, @@ -61,11 +63,72 @@ Future runWithLogging( environment: environment, includeParentEnvironment: true, runInShell: Platform.isWindows); - process.stdout.listen((out) => log(systemEncoding.decode(out))); - process.stderr.listen((err) => log(systemEncoding.decode(err))); + process.stdout.listen((out) => log(systemEncoding.decode(out).trimRight())); + process.stderr.listen((out) => log(systemEncoding.decode(out).trimRight())); return process; } +class TaskScheduler { + final Queue<_SchedulerTask> _taskQueue = + Queue<_SchedulerTask>(); + bool _isActive = false; + + int get queueCount => _taskQueue.length; + + Future _performTask(SchedulerTask task) { + return task.perform().timeout(task.timeoutDuration); + } + + Future schedule(SchedulerTask task) { + if (!_isActive) { + _isActive = true; + return _performTask(task).whenComplete(_next); + } + + final taskResult = Completer(); + _taskQueue.add(_SchedulerTask(task, taskResult)); + return taskResult.future; + } + + void _next() { + assert(_isActive); + if (_taskQueue.isEmpty) { + _isActive = false; + return; + } + + final first = _taskQueue.removeFirst(); + first.taskResult.complete(_performTask(first.task).whenComplete(_next)); + } +} + +// Internal unit of scheduling. +class _SchedulerTask { + final SchedulerTask task; + final Completer taskResult; + + _SchedulerTask(this.task, this.taskResult); +} + +// Public working data structure. +abstract class SchedulerTask { + late Duration timeoutDuration; + Future perform(); +} + +class ClosureTask extends SchedulerTask { + final Future Function() _closure; + + ClosureTask(this._closure, {required Duration timeoutDuration}) { + this.timeoutDuration = timeoutDuration; + } + + @override + Future perform() { + return _closure(); + } +} + /// A pattern which matches a possible path. /// /// This pattern is essentially "possibly some letters and colons, followed by a diff --git a/pkgs/dart_services/protos/dart_services.proto b/pkgs/dart_services/protos/dart_services.proto deleted file mode 100644 index 47353671c..000000000 --- a/pkgs/dart_services/protos/dart_services.proto +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// 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. - -syntax = "proto3"; - -package dart_services.api; - -message CompileRequest { - // The Dart source. - string source = 1; - - // Return the Dart to JS source map; optional (defaults to false). - bool returnSourceMap = 2; -} - -/// Compile request for a multiple file set. -message CompileFilesRequest { - // The Dart source files set. map of { filename1:sourcecode1 .. filenameN:sourcecodeN } - map files = 1; - - // Return the Dart to JS source map; optional (defaults to false). - bool returnSourceMap = 2; -} - -message CompileDDCRequest { - // The Dart source. - string source = 1; -} - -/// DDC Compile request for a multiple file set. -message CompileFilesDDCRequest { - // The Dart source files set. map of { filename1:sourcecode1 .. filenameN:sourcecodeN } - map files = 1; -} - -message FlutterBuildResponse { - map artifacts = 1; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -message SourceRequest { - // The Dart source. - string source = 1; - - // The offset within source to operate at. - int32 offset = 2; -} - -/// Multiple file set of dart source for analysis, completion, fixes, etc. -message SourceFilesRequest { - // The Dart source files set. map of { filename1:sourcecode1 .. filenameN:sourcecodeN } - map files = 1; - - // active (within editor) source filename key within files map - string activeSourceName = 2; - - // The offset within active source file to operate at. - int32 offset = 3; -} - -message AnalysisResults { - repeated AnalysisIssue issues = 1; - - // The package imports parsed from the source. - repeated string packageImports = 2; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -message AnalysisIssue { - string kind = 1; - int32 line = 2; - string message = 3; - string sourceName = 4; - bool hasFixes = 5; - int32 charStart = 6; - int32 charLength = 7; - string url = 8; - repeated DiagnosticMessage diagnosticMessages = 9; - string correction = 10; - int32 column = 11; - string code = 12; -} - -message DiagnosticMessage { - string message = 1; - int32 line = 2; - int32 charStart = 3; - int32 charLength = 4; - int32 column = 5; -} - -message VersionRequest {} - -message CompileResponse { - string result = 1; - string sourceMap = 2; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -message CompileDDCResponse { - string result = 1; - string modulesBaseUrl = 2; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -message DocumentResponse { - map info = 1; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -message CompleteResponse { - // The offset of the start of the text to be replaced. - int32 replacementOffset = 1; - - // The length of the text to be replaced. - int32 replacementLength = 2; - - repeated Completion completions = 3; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -message Completion { map completion = 1; } - -message FixesResponse { - repeated ProblemAndFixes fixes = 1; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -// Represents a problem detected during analysis, and a set of possible ways of -// resolving the problem. -message ProblemAndFixes { - repeated CandidateFix fixes = 1; - string problemMessage = 2; - int32 offset = 3; - int32 length = 4; -} - -// Represents a possible way of solving an Analysis Problem. -message CandidateFix { - string message = 1; - repeated SourceEdit edits = 2; - int32 selectionOffset = 3; - repeated LinkedEditGroup linkedEditGroups = 4; -} - -// Represents a single edit-point change to a source file. -message SourceEdit { - int32 offset = 1; - int32 length = 2; - string replacement = 3; -} - -message LinkedEditGroup { - // The positions of the regions that should be edited simultaneously. - repeated int32 positions = 1; - - // The length of the regions that should be edited simultaneously. - int32 length = 2; - - // Pre-computed suggestions for what every region might want to be changed to. - repeated LinkedEditSuggestion suggestions = 3; -} - -message LinkedEditSuggestion { - // The value that could be used to replace all of the linked edit regions. - string value = 1; - - // The kind of value being proposed. - string kind = 2; -} - -// Represents a reformatting of the code. -message FormatResponse { - // The formatted source code. - string newString = 1; - - // The (optional) new offset of the cursor; can be `null`. - int32 offset = 2; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -// The response from the `/assists` service call. -message AssistsResponse { - repeated CandidateFix assists = 1; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -// The response from the `/version` service call. -message VersionResponse { - // The Dart SDK version. - string sdkVersion = 1; - - // The full string of the Dart SDK version, including any channel name. - // - // E.g., `3.1.0-262.2.beta` vs `3.1.0`. - string sdkVersionFull = 2; - - // Removed. - string runtimeVersion = 3 [deprecated = true]; - - // Removed. - string appEngineVersion = 4 [deprecated = true]; - - // Removed. - string servicesVersion = 5 [deprecated = true]; - - // The Flutter SDK version. - string flutterVersion = 6; - - // Removed. - string flutterDartVersion = 7 [deprecated = true]; - - // Removed. - string flutterDartVersionFull = 8 [deprecated = true]; - - // Removed. - map packageVersions = 9 [deprecated = true]; - - // Package information; each package found in `pubspec.lock` is included. - repeated PackageInfo packageInfo = 10; - - // Experiments that this server is running. - repeated string experiment = 11; - - // The Flutter engine SHA, located in bin/internal/engine.version. - string flutterEngineSha = 12; - - // Make this response compatible with BadRequest - ErrorMessage error = 99; -} - -message PackageInfo { - // The name of this package. - string name = 1; - - // The selected version of this package. - string version = 2; - - // Whether this package is supported as a directly importable package, - // or simply available as a transitive dependency of a supported package. - bool supported = 3; -} - -// Response from the server when errors are thrown internally -message BadRequest { ErrorMessage error = 99; } - -// Individual error messages. -message ErrorMessage { string message = 1; } diff --git a/pkgs/dart_services/pubspec.lock b/pkgs/dart_services/pubspec.lock index 54d39bcfc..1b7de80ad 100644 --- a/pkgs/dart_services/pubspec.lock +++ b/pkgs/dart_services/pubspec.lock @@ -25,14 +25,6 @@ packages: url: "https://pub.dev" source: hosted version: "5.13.0" - angel3_mock_request: - dependency: "direct dev" - description: - name: angel3_mock_request - sha256: cd15efb464e9f877363b336a801c7d409d4b94a33e4ed4f2adef4b73e5774307 - url: "https://pub.dev" - source: hosted - version: "8.0.0" args: dependency: "direct main" description: @@ -93,10 +85,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.1" build_resolvers: dependency: transitive description: @@ -133,18 +125,10 @@ packages: dependency: transitive description: name: built_value - sha256: a8de5955205b4d1dbbbc267daddf2178bd737e4bab8987c04a500478c9651e74 - url: "https://pub.dev" - source: hosted - version: "8.6.3" - charcode: - dependency: transitive - description: - name: charcode - sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "8.7.0" checked_yaml: dependency: transitive description: @@ -197,10 +181,10 @@ packages: dependency: transitive description: name: coverage - sha256: "595a29b55ce82d53398e1bcc2cba525d7bd7c59faeb2d2540e9d42c390cfeeeb" + sha256: ac86d3abab0f165e4b8f561280ff4e066bceaac83c424dd19f1ae2c2fcd12ca9 url: "https://pub.dev" source: hosted - version: "1.6.4" + version: "1.7.1" crypto: dependency: "direct main" description: @@ -277,10 +261,10 @@ packages: dependency: "direct dev" description: name: grinder - sha256: "48495acdb3df702c55c952c6536faf11631b8401a292eb0d182ef332fc568b56" + sha256: e1996e485d2b56bb164a8585679758d488fbf567273f51c432c8733fee1f6188 url: "https://pub.dev" source: hosted - version: "0.9.4" + version: "0.9.5" http: dependency: "direct main" description: @@ -370,7 +354,7 @@ packages: source: hosted version: "0.12.16" meta: - dependency: "direct main" + dependency: transitive description: name: meta sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 @@ -426,7 +410,7 @@ packages: source: hosted version: "1.5.1" protobuf: - dependency: "direct main" + dependency: transitive description: name: protobuf sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" @@ -597,10 +581,10 @@ packages: dependency: "direct dev" description: name: test - sha256: a20ddc0723556dc6dd56094e58ec1529196d5d7774156604cb14e8445a5a82ff + sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f url: "https://pub.dev" source: hosted - version: "1.24.7" + version: "1.24.9" test_api: dependency: transitive description: @@ -613,10 +597,10 @@ packages: dependency: transitive description: name: test_core - sha256: "96382d0bc826e260b077bb496259e58bc82e90b603ab16cd5ae95dfe1dfcba8b" + sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a url: "https://pub.dev" source: hosted - version: "0.5.7" + version: "0.5.9" test_descriptor: dependency: "direct dev" description: @@ -645,10 +629,10 @@ packages: dependency: transitive description: name: vm_service - sha256: a13d5503b4facefc515c8c587ce3cf69577a7b064a9f1220e005449cf1f64aad + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "12.0.0" + version: "13.0.0" watcher: dependency: transitive description: diff --git a/pkgs/dart_services/pubspec.yaml b/pkgs/dart_services/pubspec.yaml index 851b6ae12..67e4b9344 100644 --- a/pkgs/dart_services/pubspec.yaml +++ b/pkgs/dart_services/pubspec.yaml @@ -16,16 +16,13 @@ dependencies: http: ^1.0.0 json_annotation: any logging: ^1.2.0 - meta: ^1.9.1 path: ^1.8.3 - protobuf: ^3.0.0 resp_client: ^1.2.0 shelf: ^1.4.1 shelf_router: ^1.1.4 yaml: ^3.1.2 dev_dependencies: - angel3_mock_request: ^8.0.0 async: ^2.11.0 build_runner: ^2.4.5 dart_flutter_team_lints: ^2.1.1 diff --git a/pkgs/dart_services/test/analysis_server_test.dart b/pkgs/dart_services/test/analysis_server_test.dart deleted file mode 100644 index e845326e6..000000000 --- a/pkgs/dart_services/test/analysis_server_test.dart +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file -// 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 'package:dart_services/src/analysis_server.dart'; -import 'package:dart_services/src/common.dart'; -import 'package:dart_services/src/protos/dart_services.pb.dart' as proto; -import 'package:dart_services/src/sdk.dart'; -import 'package:test/test.dart'; - -const completionCode = r''' -void main() { - int i = 0; - i. -} -'''; - -const completionFilterCode = r''' -void main() { - pr -} -'''; - -const completionLargeNamespaces = r''' -class A {} -class AB {} -class ABC {} -void main() { - var c = A -} -class ZZ {} -class a {} -'''; - -const quickFixesCode = r''' -void main() { - int i = 0 -} -'''; - -const badFormatCode = r''' -void main() -{ -int i = 0; -} -'''; - -const formattedCode = r''' -void main() { - int i = 0; -} -'''; - -const formatWithIssues = ''' -void main() { foo() } -'''; - -const lintWarningTrigger = ''' -void main() async { - var unknown; - print(unknown); -} -'''; - -void main() => defineTests(); - -void defineTests() { - late AnalysisServerWrapper analysisServer; - - /// Returns whether the completion [response] contains [expected]. - bool completionsContains(proto.CompleteResponse response, String expected) => - response.completions - .any((completion) => completion.completion['completion'] == expected); - - group('Platform SDK analysis_server', () { - late Sdk sdk; - setUp(() async { - sdk = Sdk(); - analysisServer = DartAnalysisServerWrapper(dartSdkPath: sdk.dartSdkPath); - await analysisServer.init(); - }); - - tearDown(() => analysisServer.shutdown()); - - test('simple_completion', () async { - // Just after `i.` on line 3 of [completionCode] - final results = await analysisServer.complete(completionCode, 32); - expect(results.replacementLength, 0); - expect(results.replacementOffset, 32); - final completions = - results.completions.map((c) => c.completion['completion']).toList(); - expect(completions, contains('abs')); - expect(completionsContains(results, 'codeUnitAt'), false); - }); - - // https://github.com/dart-lang/dart-pad/issues/2005 - test('Trigger lint with Dart code', () async { - final results = await analysisServer.analyze(lintWarningTrigger); - expect(results.issues.length, 1); - final issue = results.issues[0]; - expect(issue.line, 2); - expect(issue.column, 7); - expect(issue.kind, 'info'); - expect(issue.message, - 'An uninitialized variable should have an explicit type annotation.'); - expect(issue.code, 'prefer_typing_uninitialized_variables'); - }); - - test('repro #126 - completions polluted on second request', () async { - // https://github.com/dart-lang/dart-services/issues/126 - return analysisServer.complete(completionFilterCode, 17).then((results) { - return analysisServer - .complete(completionFilterCode, 17) - .then((results) { - expect(results.replacementLength, 2); - expect(results.replacementOffset, 16); - expect(completionsContains(results, 'print'), true); - expect(completionsContains(results, 'pow'), false); - }); - }); - }); - - test('import_test', () async { - // We're testing here that we don't have any path imports - we don't want - // to enable browsing the file system. - final testCode = "import '/'; main() { int a = 0; a. }"; - final results = await analysisServer.complete(testCode, 9); - final completions = results.completions; - - if (completions.isNotEmpty) { - expect(completions.every((completion) { - return completion.completion['completion']!.startsWith('dart:'); - }), true); - } - }); - - test('import_dart_core_test', () async { - // Ensure we can import dart: imports. - final testCode = "import 'dart:c'; main() { int a = 0; a. }"; - - final results = await analysisServer.complete(testCode, 14); - final completions = results.completions; - - expect( - completions.every((completion) => - completion.completion['completion']!.startsWith('dart:')), - true, - ); - expect( - completions.any((completion) => - completion.completion['completion']!.startsWith('dart:')), - true, - ); - }); - - test('import_and_other_test', () async { - final testCode = "import '/'; main() { int a = 0; a. }"; - final results = await analysisServer.complete(testCode, 34); - - expect(completionsContains(results, 'abs'), true); - }); - - test('simple_quickFix', () async { - final results = await analysisServer.getFixes(quickFixesCode, 25); - - expect(results.fixes.length, 2); - - // Fixes are not guaranteed to arrive in a particular order. - results.fixes.sort((a, b) => a.offset.compareTo(b.offset)); - - expect(results.fixes[0].offset, 20); - expect(results.fixes[0].length, 1); // We need an insertion. - - expect(results.fixes[1].offset, 24); - expect(results.fixes[1].length, 1); // We need an insertion. - - expect(results.fixes[1].fixes.length, 1); - - final candidateFix = results.fixes[1].fixes[0]; - - expect(candidateFix.message.contains(';'), true); - expect(candidateFix.edits[0].length, 0); - expect(candidateFix.edits[0].offset, 25); - expect(candidateFix.edits[0].replacement, ';'); - }); - - test('simple_format', () async { - final results = await analysisServer.format(badFormatCode, 0); - expect(results.newString, formattedCode); - }); - - test('format good code', () async { - final results = - await analysisServer.format(formattedCode.replaceAll('\n', ' '), 0); - expect(results.newString, formattedCode); - }); - - test('format with issues', () async { - final results = await analysisServer.format(formatWithIssues, 0); - expect(results.newString, formatWithIssues); - }); - - test('analyze', () async { - final results = await analysisServer.analyze(sampleCode); - expect(results.issues, isEmpty); - }); - - test('analyze with errors', () async { - final results = await analysisServer.analyze(sampleCodeError); - expect(results.issues, hasLength(1)); - }); - - test('filter completions', () async { - // just after A - final idx = 61; - expect(completionLargeNamespaces.substring(idx - 1, idx), 'A'); - final results = - await analysisServer.complete(completionLargeNamespaces, 61); - expect(completionsContains(results, 'A'), true); - expect(completionsContains(results, 'AB'), true); - expect(completionsContains(results, 'ABC'), true); - expect(completionsContains(results, 'a'), true); - expect(completionsContains(results, 'ZZ'), false); - }); - }); - - group('Flutter cached SDK analysis_server', () { - setUp(() async { - final sdk = Sdk(); - analysisServer = DartAnalysisServerWrapper(dartSdkPath: sdk.dartSdkPath); - await analysisServer.init(); - }); - - tearDown(() => analysisServer.shutdown()); - - test('analyze working Dart code', () async { - final results = await analysisServer.analyze(sampleCode); - expect(results.issues, isEmpty); - }); - - test('analyze working Flutter code', () async { - final results = await analysisServer.analyze(sampleCode); - expect(results.issues, isEmpty); - }); - }); - - //-------------------------------------------------------- - // Begin testing the multi file group files={} map entry points: - group('Platform SDK analysis_server multifile files={}', () { - late Sdk sdk; - setUp(() async { - sdk = Sdk(); - analysisServer = DartAnalysisServerWrapper(dartSdkPath: sdk.dartSdkPath); - await analysisServer.init(); - }); - - tearDown(() => analysisServer.shutdown()); - - // Now test multi file 'files:{}' source format. - const kMainDart = 'main.dart'; - - test('files={} simple_completion', () async { - // Just after `i.` on line 3 of [completionCode] - final results = await analysisServer.completeFiles( - {kMainDart: completionCode}, - const Location(kMainDart, 32), - ); - expect(results.replacementLength, 0); - expect(results.replacementOffset, 32); - final completions = - results.completions.map((c) => c.completion['completion']).toList(); - expect(completions, contains('abs')); - expect(completionsContains(results, 'codeUnitAt'), false); - }); - - // https://github.com/dart-lang/dart-pad/issues/2005 - test('files={} Trigger lint with Dart code', () async { - final results = - await analysisServer.analyzeFiles({kMainDart: lintWarningTrigger}); - expect(results.issues.length, 1); - final issue = results.issues[0]; - expect(issue.line, 2); - expect(issue.kind, 'info'); - expect(issue.message, - 'An uninitialized variable should have an explicit type annotation.'); - }); - - test('files={} repro #126 - completions polluted on second request', - () async { - final files = {kMainDart: completionFilterCode}; - final location = const Location(kMainDart, 17); - // https://github.com/dart-lang/dart-services/issues/126 - return analysisServer.completeFiles(files, location).then((results) { - return analysisServer.completeFiles(files, location).then((results) { - expect(results.replacementLength, 2); - expect(results.replacementOffset, 16); - expect(completionsContains(results, 'print'), true); - expect(completionsContains(results, 'pow'), false); - }); - }); - }); - - test('files={} import_test', () async { - // We're testing here that we don't have any path imports - we don't want - // to enable browsing the file system. - final testCode = "import '/'; main() { int a = 0; a. }"; - - final results = await analysisServer.completeFiles( - {kMainDart: testCode}, - const Location(kMainDart, 9), - ); - final completions = results.completions; - - if (completions.isNotEmpty) { - expect(completions.every((completion) { - return completion.completion['completion']!.startsWith('dart:'); - }), true); - } - }); - - test('files={} import_dart_core_test', () async { - // Ensure we can import dart: imports. - final testCode = "import 'dart:c'; main() { int a = 0; a. }"; - - final results = await analysisServer.completeFiles( - {kMainDart: testCode}, - const Location(kMainDart, 14), - ); - final completions = results.completions; - - expect( - completions.every((completion) => - completion.completion['completion']!.startsWith('dart:')), - true, - ); - expect( - completions.any((completion) => - completion.completion['completion']!.startsWith('dart:')), - true, - ); - }); - - test('files={} import_and_other_test', () async { - final testCode = "import '/'; main() { int a = 0; a. }"; - - final results = await analysisServer.completeFiles( - {kMainDart: testCode}, - const Location(kMainDart, 34), - ); - - expect(completionsContains(results, 'abs'), true); - }); - - test('files={} myRandomName.dart + simple_quickFix', () async { - final results = await analysisServer.getFixesMulti( - {'myRandomName.dart': quickFixesCode}, - const Location('myRandomName.dart', 25), - ); - - expect(results.fixes.length, 2); - - // Fixes are not guaranteed to arrive in a particular order. - results.fixes.sort((a, b) => a.offset.compareTo(b.offset)); - - expect(results.fixes[0].offset, 20); - expect(results.fixes[0].length, 1); // We need an insertion. - - expect(results.fixes[1].offset, 24); - expect(results.fixes[1].length, 1); // We need an insertion. - - expect(results.fixes[1].fixes.length, 1); - - final candidateFix = results.fixes[1].fixes[0]; - - expect(candidateFix.message.contains(';'), true); - expect(candidateFix.edits[0].length, 0); - expect(candidateFix.edits[0].offset, 25); - expect(candidateFix.edits[0].replacement, ';'); - }); - - test('files={} analyze', () async { - final results = - await analysisServer.analyzeFiles({kMainDart: sampleCode}); - expect(results.issues, isEmpty); - }); - - test('files={} analyze with errors', () async { - final results = - await analysisServer.analyzeFiles({kMainDart: sampleCodeError}); - expect(results.issues, hasLength(1)); - }); - - test('files={} filter completions', () async { - // just after A - final idx = 61; - expect(completionLargeNamespaces.substring(idx - 1, idx), 'A'); - final results = await analysisServer.completeFiles( - {kMainDart: completionLargeNamespaces}, - const Location(kMainDart, 61), - ); - expect(completionsContains(results, 'A'), true); - expect(completionsContains(results, 'AB'), true); - expect(completionsContains(results, 'ABC'), true); - expect(completionsContains(results, 'a'), true); - expect(completionsContains(results, 'ZZ'), false); - }); - }); -} diff --git a/pkgs/dart_services/test/analysis_test.dart b/pkgs/dart_services/test/analysis_test.dart new file mode 100644 index 000000000..d057eba75 --- /dev/null +++ b/pkgs/dart_services/test/analysis_test.dart @@ -0,0 +1,329 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// 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 'package:dart_services/src/analysis.dart'; +import 'package:dart_services/src/sdk.dart'; +import 'package:dart_services/src/shared/model.dart' as api; +import 'package:test/test.dart'; + +import 'src/sample_code.dart'; + +void main() => defineTests(); + +void defineTests() { + group('analysis', () { + final sdk = Sdk(); + late DartAnalysisServerWrapper analysisServer; + + setUpAll(() async { + analysisServer = DartAnalysisServerWrapper(sdkPath: sdk.dartSdkPath); + await analysisServer.init(); + }); + + tearDownAll(() => analysisServer.shutdown()); + + test('simple_completion', () async { + // Just after `i.` on line 3 of [completionCode] + final results = await analysisServer.completeV3(completionCode, 32); + expect(results.replacementLength, 0); + expect(results.replacementOffset, 32); + final completions = results.suggestions.map((c) => c.completion).toList(); + expect(completions, contains('abs')); + expect(completionsContains(results, 'codeUnitAt'), false); + }); + + // https://github.com/dart-lang/dart-pad/issues/2005 + test('Trigger lint with Dart code', () async { + final results = await analysisServer.analyze(lintWarningTrigger); + expect(results.issues.length, 1); + final issue = results.issues[0]; + expect(issue.location.line, 2); + expect(issue.location.column, 7); + expect(issue.kind, 'info'); + expect(issue.message, + 'An uninitialized variable should have an explicit type annotation.'); + expect(issue.code, 'prefer_typing_uninitialized_variables'); + }); + + test('repro #126 - completions polluted on second request', () async { + // https://github.com/dart-lang/dart-services/issues/126 + return analysisServer + .completeV3(completionFilterCode, 17) + .then((results) { + return analysisServer + .completeV3(completionFilterCode, 17) + .then((results) { + expect(results.replacementLength, 2); + expect(results.replacementOffset, 16); + expect(completionsContains(results, 'print'), true); + expect(completionsContains(results, 'pow'), false); + }); + }); + }); + + test('import_test', () async { + // We're testing here that we don't have any path imports - we don't want + // to enable browsing the file system. + final testCode = "import '/'; main() { int a = 0; a. }"; + final results = await analysisServer.completeV3(testCode, 9); + final completions = results.suggestions; + + if (completions.isNotEmpty) { + expect(completions.every((completion) { + return completion.completion.startsWith('dart:') || + completion.completion.startsWith('package:'); + }), true); + } + }); + + test('import_dart_core_test', () async { + // Ensure we can import dart: imports. + final testCode = "import 'dart:c'; main() { int a = 0; a. }"; + + final results = await analysisServer.completeV3(testCode, 14); + final completions = results.suggestions; + + expect( + completions + .every((completion) => completion.completion.startsWith('dart:')), + true, + ); + expect( + completions + .any((completion) => completion.completion.startsWith('dart:')), + true, + ); + }); + + test('import_and_other_test', () async { + final testCode = "import '/'; main() { int a = 0; a. }"; + final results = await analysisServer.completeV3(testCode, 34); + + expect(completionsContains(results, 'abs'), true); + }); + + test('simple_quickFix', () async { + final results = await analysisServer.fixesV3(quickFixesCode, 25); + final changes = results.fixes; + + expect(changes, isNotEmpty); + + // "Ignore 'unused_local_variable' for this line" + expect(changes.map((e) => e.message), contains(startsWith('Ignore '))); + + // "Insert ';'" + expect(changes.map((e) => e.message), contains(startsWith('Insert '))); + expect( + changes.map((e) => e.edits.first.replacement), contains(equals(';'))); + }); + + test('simple_format', () async { + final results = await analysisServer.format(badFormatCode, 0); + expect(results.source, formattedCode); + }); + + test('format good code', () async { + final results = + await analysisServer.format(formattedCode.replaceAll('\n', ' '), 0); + expect(results.source, formattedCode); + }); + + test('format with issues', () async { + final results = await analysisServer.format(formatWithIssues, 0); + expect(results.source, formatWithIssues); + }); + + test('analyze', () async { + final results = await analysisServer.analyze(sampleCode); + expect(results.issues, isEmpty); + }); + + test('analyze with errors', () async { + final results = await analysisServer.analyze(sampleCodeError); + expect(results.issues, hasLength(1)); + }); + + test('filter completions', () async { + // just after A + final idx = 61; + expect(completionLargeNamespaces.substring(idx - 1, idx), 'A'); + final results = + await analysisServer.completeV3(completionLargeNamespaces, 61); + expect(completionsContains(results, 'A'), true); + expect(completionsContains(results, 'AB'), true); + expect(completionsContains(results, 'ABC'), true); + expect(completionsContains(results, 'a'), true); + expect(completionsContains(results, 'ZZ'), false); + }); + + test('analyze working Dart code', () async { + final results = await analysisServer.analyze(sampleCode); + expect(results.issues, isEmpty); + }); + + test('analyze working Flutter code', () async { + final results = await analysisServer.analyze(sampleCodeFlutter); + expect(results.issues, isEmpty); + }); + }); + + group('analysis flutter', () { + final sdk = Sdk(); + late DartAnalysisServerWrapper analysisServer; + + setUpAll(() async { + analysisServer = DartAnalysisServerWrapper(sdkPath: sdk.dartSdkPath); + await analysisServer.init(); + }); + + tearDownAll(() async { + await analysisServer.shutdown(); + }); + + test('analyze counter app', () async { + final results = await analysisServer.analyze(sampleCodeFlutterCounter); + expect(results.issues, isEmpty); + }); + + test('analyze Draggable Physics sample', () async { + final results = + await analysisServer.analyze(sampleCodeFlutterDraggableCard); + expect(results.issues, isEmpty); + }); + + test('reports errors with Flutter code', () async { + final results = await analysisServer.analyze(''' +import 'package:flutter/material.dart'; + +String x = 7; + +void main() async { + runApp(MaterialApp( + debugShowCheckedModeBanner: false, home: Scaffold(body: HelloWorld()))); +} + +class HelloWorld extends StatelessWidget { + @override + Widget build(context) => const Center(child: Text('Hello world')); +} +'''); + expect(results.issues, hasLength(1)); + final issue = results.issues[0]; + expect(issue.location.line, 3); + expect(issue.kind, 'error'); + expect( + issue.message, + "A value of type 'int' can't be assigned to a variable of type " + "'String'."); + }); + + // https://github.com/dart-lang/dart-pad/issues/2005 + test('reports lint with Flutter code', () async { + final results = await analysisServer.analyze(''' +import 'package:flutter/material.dart'; + +void main() async { + var unknown; + print(unknown); + + runApp(MaterialApp( + debugShowCheckedModeBanner: false, home: Scaffold(body: HelloWorld()))); +} + +class HelloWorld extends StatelessWidget { + @override + Widget build(context) => const Center(child: Text('Hello world')); +} +'''); + expect(results.issues, hasLength(1)); + final issue = results.issues[0]; + expect(issue.location.line, 4); + expect(issue.kind, 'info'); + expect(issue.message, + 'An uninitialized variable should have an explicit type annotation.'); + }); + + test('analyze counter app', () async { + final results = await analysisServer.analyze(sampleCodeFlutterCounter); + expect(results.issues, isEmpty); + }); + + test('analyze Draggable Physics sample', () async { + final results = + await analysisServer.analyze(sampleCodeFlutterDraggableCard); + expect(results.issues, isEmpty); + }); + + test('analyze counter app', () async { + final results = await analysisServer.analyze(sampleCodeFlutterCounter); + expect(results.issues, isEmpty); + }); + + test('analyze Draggable Physics sample', () async { + final results = + await analysisServer.analyze(sampleCodeFlutterDraggableCard); + expect(results.issues, isEmpty); + }); + }); +} + +/// Returns whether the completion [response] contains [expected]. +bool completionsContains(api.CompleteResponse response, String expected) { + return response.suggestions + .any((completion) => completion.completion == expected); +} + +const completionCode = r''' +void main() { + int i = 0; + i. +} +'''; + +const completionFilterCode = r''' +void main() { + pr +} +'''; + +const completionLargeNamespaces = r''' +class A {} +class AB {} +class ABC {} +void main() { + var c = A +} +class ZZ {} +class a {} +'''; + +const quickFixesCode = r''' +void main() { + int i = 0 +} +'''; + +const badFormatCode = r''' +void main() +{ +int i = 0; +} +'''; + +const formattedCode = r''' +void main() { + int i = 0; +} +'''; + +const formatWithIssues = ''' +void main() { foo() } +'''; + +const lintWarningTrigger = ''' +void main() async { + var unknown; + print(unknown); +} +'''; diff --git a/pkgs/dart_services/test/redis_cache_test.dart b/pkgs/dart_services/test/caching_test.dart similarity index 98% rename from pkgs/dart_services/test/redis_cache_test.dart rename to pkgs/dart_services/test/caching_test.dart index 3e7297b31..c1170be2f 100644 --- a/pkgs/dart_services/test/redis_cache_test.dart +++ b/pkgs/dart_services/test/caching_test.dart @@ -5,13 +5,14 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_services/src/common_server_impl.dart'; +import 'package:dart_services/src/caching.dart'; import 'package:dart_services/src/sdk.dart'; -import 'package:dart_services/src/server_cache.dart'; import 'package:logging/logging.dart'; import 'package:synchronized/synchronized.dart'; import 'package:test/test.dart'; +// todo: move this away from using a log for testing + void main() async { final hasRedis = await hasRedisServer(); defineTests(hasRedis); diff --git a/pkgs/dart_services/test/common_server_api_protobuf_test.dart b/pkgs/dart_services/test/common_server_api_protobuf_test.dart deleted file mode 100644 index a02ffb113..000000000 --- a/pkgs/dart_services/test/common_server_api_protobuf_test.dart +++ /dev/null @@ -1,740 +0,0 @@ -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file -// 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'; -import 'dart:convert'; - -import 'package:dart_services/src/common.dart'; -import 'package:dart_services/src/common_server_api.dart'; -import 'package:dart_services/src/common_server_impl.dart'; -import 'package:dart_services/src/protos/dart_services.pb.dart' as proto; -import 'package:dart_services/src/sdk.dart'; -import 'package:dart_services/src/server_cache.dart'; -import 'package:logging/logging.dart'; -import 'package:protobuf/protobuf.dart'; -import 'package:shelf/shelf_io.dart' as shelf_io; -import 'package:test/test.dart'; - -import 'src/utils.dart'; - -const preFormattedCode = r''' -void main() -{ -int i = 0; -} -'''; - -const postFormattedCode = r''' -void main() { - int i = 0; -} -'''; - -const formatBadCode = r''' -void main() -{ - print('foo') -} -'''; - -void main() => defineTests(); - -void defineTests() { - late CommonServerApi commonServerApi; - late CommonServerImpl commonServerImpl; - - Future sendPostRequest( - String path, - GeneratedMessage? message, - ) async { - final uri = Uri.parse('/api/$path'); - final request = MockHttpRequest('POST', uri); - request.headers.add('content-type', jsonContentType); - if (message != null) { - request.add(utf8.encode(json.encode(message.toProto3Json()))); - } - await request.close(); - await shelf_io.handleRequest(request, commonServerApi.router.call); - return request.response; - } - - Future sendGetRequest( - String path, - ) async { - final uri = Uri.parse('/api/$path'); - final request = MockHttpRequest('GET', uri); - request.headers.add('content-type', jsonContentType); - await request.close(); - await shelf_io.handleRequest(request, commonServerApi.router.call); - return request.response; - } - - group('CommonServerProto JSON', () { - final sdk = Sdk(); - setUpAll(() async { - final ServerCache cache = MockCache(); - commonServerImpl = CommonServerImpl(sdk, cache); - commonServerApi = CommonServerApi(commonServerImpl); - await commonServerImpl.init(); - - // Some piece of initialization doesn't always happen fast enough for this - // request to work in time for the test. So try it here until the server - // returns something valid. - // TODO(jcollins-g): determine which piece of initialization isn't - // happening and deal with that in warmup/init. - { - var decodedJson = {}; - final jsonData = proto.SourceRequest()..source = sampleCodeError; - while (decodedJson.isEmpty) { - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - expect(response.headers['content-type'], - ['application/json; charset=utf-8']); - final data = await response.transform(utf8.decoder).join(); - decodedJson = json.decode(data) as Map; - } - } - }); - - tearDownAll(() async { - await commonServerImpl.shutdown(); - }); - - setUp(() { - log.onRecord.listen((LogRecord rec) { - print('${rec.level.name}: ${rec.time}: ${rec.message}'); - }); - }); - - tearDown(log.clearListeners); - - test('analyze Dart', () async { - final request = proto.SourceRequest()..source = sampleCode; - final response = - await sendPostRequest('dartservices/v2/analyze', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.AnalysisResults()..mergeFromProto3Json(data); - expect(reply.issues, isEmpty); - expect(reply.packageImports, isEmpty); - }); - - test('analyze Flutter', () async { - final request = proto.SourceRequest()..source = sampleCodeFlutter; - final response = - await sendPostRequest('dartservices/v2/analyze', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.AnalysisResults()..mergeFromProto3Json(data); - expect(reply.issues, isEmpty); - expect(reply.packageImports, ['flutter']); - }); - - test('analyze errors', () async { - final request = proto.SourceRequest()..source = sampleCodeError; - late proto.AnalysisResults reply; - final response = - await sendPostRequest('dartservices/v2/analyze', request); - expect(response.statusCode, 200); - expect(response.headers['content-type'], - ['application/json; charset=utf-8']); - final data = json.decode(await response.transform(utf8.decoder).join()); - reply = proto.AnalysisResults()..mergeFromProto3Json(data); - expect(reply.issues, hasLength(1)); - expect(reply.issues[0].kind, 'error'); - expect(reply.issues[0].line, 2); - expect(reply.issues[0].sourceName, 'main.dart'); - expect(reply.issues[0].message, "Expected to find ';'."); - expect(reply.issues[0].hasFixes, true); - expect(reply.issues[0].charStart, 29); - expect(reply.issues[0].charLength, 1); - }); - - test('analyze negative-test noSource', () async { - final request = proto.SourceRequest(); - final response = - await sendPostRequest('dartservices/v2/analyze', request); - expect(response.statusCode, 400); - }); - - test('compile', () async { - final request = proto.CompileRequest()..source = sampleCode; - final response = - await sendPostRequest('dartservices/v2/compile', request); - - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompileResponse()..mergeFromProto3Json(data); - expect(reply.result, isNotEmpty); - }); - - test('compile error', () async { - final request = proto.CompileRequest()..source = sampleCodeError; - final response = - await sendPostRequest('dartservices/v2/compile', request); - expect(response.statusCode, 400); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompileResponse()..mergeFromProto3Json(data); - expect(reply.error.message, contains('Error: Expected')); - }); - - test('compile negative-test noSource', () async { - final request = proto.CompileRequest(); - final response = - await sendPostRequest('dartservices/v2/compile', request); - expect(response.statusCode, 400); - }); - - test('compileDDC', () async { - final request = proto.CompileRequest()..source = sampleCode; - final response = - await sendPostRequest('dartservices/v2/compileDDC', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompileDDCResponse()..mergeFromProto3Json(data); - expect(reply.result, isNotEmpty); - }); - - test('complete', () async { - final request = proto.SourceRequest() - ..source = 'void main() {print("foo");}' - ..offset = 1; - final response = - await sendPostRequest('dartservices/v2/complete', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompleteResponse()..mergeFromProto3Json(data); - expect(reply.completions, isNotEmpty); - }); - - test('complete no data', () async { - final request = await sendPostRequest( - 'dartservices/v2/complete', proto.SourceRequest()); - expect(request.statusCode, 400); - }); - - test('complete param missing', () async { - final request = proto.SourceRequest()..offset = 1; - final response = - await sendPostRequest('dartservices/v2/complete', request); - expect(response.statusCode, 400); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompleteResponse()..mergeFromProto3Json(data); - expect(reply.error.message, 'Missing parameter: \'source\''); - }); - - test('complete param missing 2', () async { - final request = proto.SourceRequest() - ..source = 'void main() {print("foo");}'; - final response = - await sendPostRequest('dartservices/v2/complete', request); - expect(response.statusCode, 400); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompleteResponse()..mergeFromProto3Json(data); - expect(reply.error.message, 'Missing parameter: \'offset\''); - }); - - test('document', () async { - final request = proto.SourceRequest() - ..source = 'void main() {print("foo");}' - ..offset = 17; - final response = - await sendPostRequest('dartservices/v2/document', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.DocumentResponse()..mergeFromProto3Json(data); - expect(reply.info, isNotEmpty); - }); - - test('document little data', () async { - final request = proto.SourceRequest() - ..source = 'void main() {print("foo");}' - ..offset = 2; - final response = - await sendPostRequest('dartservices/v2/document', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.DocumentResponse()..mergeFromProto3Json(data); - expect(reply.info, isEmpty); - }); - - test('document no data', () async { - final request = proto.SourceRequest() - ..source = 'void main() {print("foo");}' - ..offset = 12; - final response = - await sendPostRequest('dartservices/v2/document', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.DocumentResponse()..mergeFromProto3Json(data); - expect(reply.info, isEmpty); - }); - - test('document negative-test noSource', () async { - final request = proto.SourceRequest()..offset = 12; - final response = - await sendPostRequest('dartservices/v2/document', request); - expect(response.statusCode, 400); - }); - - test('document negative-test noOffset', () async { - final request = proto.SourceRequest() - ..source = 'void main() {print("foo");}'; - final response = - await sendPostRequest('dartservices/v2/document', request); - expect(response.statusCode, 400); - }); - - test('format', () async { - final request = proto.SourceRequest()..source = preFormattedCode; - final response = await sendPostRequest('dartservices/v2/format', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.FormatResponse()..mergeFromProto3Json(data); - expect(reply.newString, postFormattedCode); - }); - - test('format bad code', () async { - final request = proto.SourceRequest()..source = formatBadCode; - final response = await sendPostRequest('dartservices/v2/format', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.FormatResponse()..mergeFromProto3Json(data); - expect(reply.newString, formatBadCode); - }); - - test('format position', () async { - final request = proto.SourceRequest() - ..source = preFormattedCode - ..offset = 21; - final response = await sendPostRequest('dartservices/v2/format', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.FormatResponse()..mergeFromProto3Json(data); - expect(reply.newString, postFormattedCode); - expect(reply.offset, 24); - }); - - test('fix', () async { - final quickFixesCode = ''' -import 'dart:async'; -void main() { - int i = 0; -} -'''; - final request = proto.SourceRequest() - ..source = quickFixesCode - ..offset = 10; - final response = await sendPostRequest('dartservices/v2/fixes', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.FixesResponse()..mergeFromProto3Json(data); - final fixes = reply.fixes; - expect(fixes.length, 1); - final problemAndFix = fixes[0]; - expect(problemAndFix.problemMessage, isNotNull); - }); - - test('fixes completeness', () async { - final request = proto.SourceRequest() - ..source = ''' -void main() { - for (int i = 0; i < 4; i++) { - print('hello \$i') - } -} -''' - ..offset = 67; - final response = await sendPostRequest('dartservices/v2/fixes', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.FixesResponse()..mergeFromProto3Json(data); - expect(reply.fixes[0].fixes[0].message, "Insert ';'"); - expect(reply.fixes[0].fixes[0].edits[0].offset, 67); - expect(reply.fixes[0].fixes[0].edits[0].length, 0); - expect(reply.fixes[0].fixes[0].edits[0].replacement, ';'); - expect(reply.fixes[0].problemMessage, "Expected to find ';'."); - expect(reply.fixes[0].offset, 66); - expect(reply.fixes[0].length, 1); - }); - - test('assist', () async { - final assistCode = ''' -main() { - int v = 0; -} -'''; - final request = proto.SourceRequest() - ..source = assistCode - ..offset = 15; - final response = - await sendPostRequest('dartservices/v2/assists', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.AssistsResponse()..mergeFromProto3Json(data); - final assists = reply.assists; - expect(assists, hasLength(3)); - expect(assists.first.edits, isNotNull); - expect(assists.first.edits, hasLength(1)); - expect( - assists.where((candidateFix) => - candidateFix.message == 'Remove type annotation'), - isNotEmpty); - }); - - test('version', () async { - final response = await sendPostRequest('dartservices/v2/version', null); - expect(response.statusCode, 200); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data['sdkVersion'], isNotNull); - expect(data['flutterVersion'], isNotNull); - }); - - test('version', () async { - final response = await sendGetRequest('dartservices/v2/version'); - expect(response.statusCode, 200); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data['sdkVersion'], isNotNull); - expect(data['flutterVersion'], isNotNull); - }); - }); - - //----------------------------------------------------------------- - // Beginning of multi file files={} group tests: - group('CommonServerProto JSON Multi File Group files={}', () { - final sdk = Sdk(); - setUpAll(() async { - final cache = MockCache(); - commonServerImpl = CommonServerImpl(sdk, cache); - commonServerApi = CommonServerApi(commonServerImpl); - await commonServerImpl.init(); - - // Some piece of initialization doesn't always happen fast enough for this - // request to work in time for the test. So try it here until the server - // returns something valid. - // TODO(jcollins-g): determine which piece of initialization isn't - // happening and deal with that in warmup/init. - { - var decodedJson = {}; - final jsonData = proto.SourceRequest()..source = sampleCodeError; - while (decodedJson.isEmpty) { - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - expect(response.headers['content-type'], - ['application/json; charset=utf-8']); - final data = await response.transform(utf8.decoder).join(); - decodedJson = json.decode(data) as Map; - } - } - }); - - tearDownAll(() async { - await commonServerImpl.shutdown(); - }); - - setUp(() { - log.onRecord.listen((LogRecord rec) { - print('${rec.level.name}: ${rec.time}: ${rec.message}'); - }); - }); - - tearDown(log.clearListeners); - - test('analyzeFiles Dart files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: sampleCode}); - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.AnalysisResults()..mergeFromProto3Json(data); - expect(reply.issues, isEmpty); - expect(reply.packageImports, isEmpty); - }); - - test('analyzeFiles Flutter files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: sampleCodeFlutter}); - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.AnalysisResults()..mergeFromProto3Json(data); - expect(reply.issues, isEmpty); - expect(reply.packageImports, ['flutter']); - }); - - test('analyzeFiles errors files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: sampleCodeError}); - late proto.AnalysisResults reply; - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', request); - expect(response.statusCode, 200); - expect(response.headers['content-type'], - ['application/json; charset=utf-8']); - final data = json.decode(await response.transform(utf8.decoder).join()); - reply = proto.AnalysisResults()..mergeFromProto3Json(data); - expect(reply.issues, hasLength(1)); - expect(reply.issues[0].kind, 'error'); - expect(reply.issues[0].line, 2); - expect(reply.issues[0].sourceName, 'main.dart'); - expect(reply.issues[0].message, "Expected to find ';'."); - expect(reply.issues[0].hasFixes, true); - expect(reply.issues[0].charStart, 29); - expect(reply.issues[0].charLength, 1); - }); - - test('analyzeFiles negative-test noSource files={}', () async { - final request = proto.SourceFilesRequest(); - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', request); - expect(response.statusCode, 400); - }); - - test('compileFiles files={}', () async { - final request = proto.CompileFilesRequest() - ..files.addAll({kMainDart: sampleCode}); - final response = - await sendPostRequest('dartservices/v2/compileFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompileResponse()..mergeFromProto3Json(data); - expect(reply.result, isNotEmpty); - }); - - test('compileFiles 2 simple import files set in files={}', () async { - final request = proto.CompileFilesRequest() - ..files.addAll({ - kMainDart: sampleCodeMultiFoo, - 'bar.dart': sampleCodeMultiBar, - }) - ..returnSourceMap = false; - final response = - await sendPostRequest('dartservices/v2/compileFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompileResponse()..mergeFromProto3Json(data); - expect(reply.result, isNotEmpty); - }); - - test('compileFiles error files={}', () async { - final request = proto.CompileFilesRequest() - ..files.addAll({kMainDart: sampleCodeError}); - final response = - await sendPostRequest('dartservices/v2/compileFiles', request); - expect(response.statusCode, 400); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompileResponse()..mergeFromProto3Json(data); - expect(reply.error.message, contains('Error: Expected')); - }); - - test('compileFiles negative-test noSource files={}', () async { - final request = proto.CompileFilesRequest(); - final response = - await sendPostRequest('dartservices/v2/compileFiles', request); - expect(response.statusCode, 400); - }); - - test('compileFilesDDC mymain.dart files={}', () async { - final request = proto.CompileFilesDDCRequest() - ..files.addAll({'mymain.dart': sampleCode}); - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompileDDCResponse()..mergeFromProto3Json(data); - expect(reply.result, isNotEmpty); - }); - - test('compileFilesDDC 3 files set in files={}', () async { - final request = proto.CompileFilesDDCRequest() - ..files.addAll({ - kMainDart: sampleCode3PartLibraryMain, - 'discdata.dart': sampleCode3PartDiscDataPartOfTestAnim, - 'various.dart': sampleCode3PartVariousPartOfTestAnim - }); - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompileDDCResponse()..mergeFromProto3Json(data); - expect(reply.result, isNotEmpty); - }); - - test('completeFiles files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: 'void main() {print("foo");}'}) - ..activeSourceName = kMainDart - ..offset = 1; - final response = - await sendPostRequest('dartservices/v2/completeFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompleteResponse()..mergeFromProto3Json(data); - expect(reply.completions, isNotEmpty); - }); - - test('completeFiles no data files={}', () async { - final request = await sendPostRequest( - 'dartservices/v2/completeFiles', proto.SourceFilesRequest()); - expect(request.statusCode, 400); - }); - - test('completeFiles param missing files={}', () async { - final request = proto.SourceFilesRequest()..offset = 1; - final response = - await sendPostRequest('dartservices/v2/completeFiles', request); - expect(response.statusCode, 400); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompleteResponse()..mergeFromProto3Json(data); - expect(reply.error.message, 'Missing parameter: \'files\''); - }); - - test('completeFiles param missing 2 files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: 'void main() {print("foo");}'}); - final response = - await sendPostRequest('dartservices/v2/completeFiles', request); - expect(response.statusCode, 400); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.CompleteResponse()..mergeFromProto3Json(data); - expect(reply.error.message, 'Missing parameter: \'activeSourceName\''); - }); - - test('documentFiles files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: 'void main() {print("foo");}'}) - ..activeSourceName = kMainDart - ..offset = 17; - final response = - await sendPostRequest('dartservices/v2/documentFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.DocumentResponse()..mergeFromProto3Json(data); - expect(reply.info, isNotEmpty); - }); - - test('documentFiles little data files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: 'void main() {print("foo");}'}) - ..activeSourceName = kMainDart - ..offset = 2; - final response = - await sendPostRequest('dartservices/v2/documentFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.DocumentResponse()..mergeFromProto3Json(data); - expect(reply.info, isEmpty); - }); - - test('documentFiles no data files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: 'void main() {print("foo");}'}) - ..activeSourceName = kMainDart - ..offset = 12; - final response = - await sendPostRequest('dartservices/v2/documentFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.DocumentResponse()..mergeFromProto3Json(data); - expect(reply.info, isEmpty); - }); - - test('documentFiles negative-test noSource files={}', () async { - final request = proto.SourceFilesRequest()..offset = 12; - final response = - await sendPostRequest('dartservices/v2/documentFiles', request); - expect(response.statusCode, 400); - }); - - test('documentFiles negative-test noActiveSource noOffset files={}', - () async { - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: 'void main() {print("foo");}'}); - final response = - await sendPostRequest('dartservices/v2/documentFiles', request); - expect(response.statusCode, 400); - }); - - test('fix2 files={}', () async { - final quickFixesCode = ''' -import 'dart:async'; -void main() { - int i = 0; -} -'''; - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: quickFixesCode}) - ..activeSourceName = kMainDart - ..offset = 10; - final response = - await sendPostRequest('dartservices/v2/fixesFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.FixesResponse()..mergeFromProto3Json(data); - final fixes = reply.fixes; - expect(fixes.length, 1); - final problemAndFix = fixes[0]; - expect(problemAndFix.problemMessage, isNotNull); - }); - - test('fixesFiles completeness files={}', () async { - final request = proto.SourceFilesRequest() - ..files.addAll({ - kMainDart: ''' -void main() { - for (int i = 0; i < 4; i++) { - print('hello \$i') - } -} -''' - }) - ..activeSourceName = kMainDart - ..offset = 67; - final response = - await sendPostRequest('dartservices/v2/fixesFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.FixesResponse()..mergeFromProto3Json(data); - expect(reply.fixes[0].fixes[0].message, "Insert ';'"); - expect(reply.fixes[0].fixes[0].edits[0].offset, 67); - expect(reply.fixes[0].fixes[0].edits[0].length, 0); - expect(reply.fixes[0].fixes[0].edits[0].replacement, ';'); - expect(reply.fixes[0].problemMessage, "Expected to find ';'."); - expect(reply.fixes[0].offset, 66); - expect(reply.fixes[0].length, 1); - }); - - test('assist2 files={}', () async { - final assistCode = ''' -main() { - int v = 0; -} -'''; - final request = proto.SourceFilesRequest() - ..files.addAll({kMainDart: assistCode}) - ..activeSourceName = kMainDart - ..offset = 15; - final response = - await sendPostRequest('dartservices/v2/assistsFiles', request); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - final reply = proto.AssistsResponse()..mergeFromProto3Json(data); - final assists = reply.assists; - expect(assists, hasLength(3)); - expect(assists.first.edits, isNotNull); - expect(assists.first.edits, hasLength(1)); - expect( - assists.where((candidateFix) => - candidateFix.message == 'Remove type annotation'), - isNotEmpty); - }); - }); - // End of multi file files={} tests group. -} diff --git a/pkgs/dart_services/test/common_server_api_test.dart b/pkgs/dart_services/test/common_server_api_test.dart deleted file mode 100644 index f0b6f321f..000000000 --- a/pkgs/dart_services/test/common_server_api_test.dart +++ /dev/null @@ -1,1086 +0,0 @@ -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file -// 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'; -import 'dart:convert'; - -import 'package:dart_services/src/common.dart'; -import 'package:dart_services/src/common_server_api.dart'; -import 'package:dart_services/src/common_server_impl.dart'; -import 'package:dart_services/src/sdk.dart'; -import 'package:dart_services/src/server_cache.dart'; -import 'package:logging/logging.dart'; -import 'package:shelf/shelf_io.dart' as shelf_io; -import 'package:test/test.dart'; - -import 'src/utils.dart'; - -const preFormattedCode = r''' -void main() -{ -int i = 0; -} -'''; - -const postFormattedCode = r''' -void main() { - int i = 0; -} -'''; - -const formatBadCode = r''' -void main() -{ - print('foo') -} -'''; - -void main() => defineTests(); - -void defineTests() { - late CommonServerApi commonServerApi; - late CommonServerImpl commonServerImpl; - - Future sendPostRequest( - String path, - dynamic jsonData, - ) async { - final uri = Uri.parse('/api/$path'); - final request = MockHttpRequest('POST', uri); - request.headers.add('content-type', jsonContentType); - request.add(utf8.encode(json.encode(jsonData))); - await request.close(); - await shelf_io.handleRequest(request, commonServerApi.router.call); - return request.response; - } - - Future sendGetRequest( - String path, - ) async { - final uri = Uri.parse('/api/$path'); - final request = MockHttpRequest('GET', uri); - request.headers.add('content-type', jsonContentType); - await request.close(); - await shelf_io.handleRequest(request, commonServerApi.router.call); - return request.response; - } - - group('CommonServerProto JSON', () { - final sdk = Sdk(); - - setUp(() async { - final ServerCache cache = MockCache(); - commonServerImpl = CommonServerImpl(sdk, cache); - commonServerApi = CommonServerApi(commonServerImpl); - await commonServerImpl.init(); - - // Some piece of initialization doesn't always happen fast enough for this - // request to work in time for the test. So try it here until the server - // returns something valid. - // TODO(jcollins-g): determine which piece of initialization isn't - // happening and deal with that in warmup/init. - { - var decodedJson = {}; - final jsonData = {'source': sampleCodeError}; - while (decodedJson.isEmpty) { - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - expect(response.headers['content-type'], - ['application/json; charset=utf-8']); - final data = await response.transform(utf8.decoder).join(); - decodedJson = json.decode(data) as Map; - } - } - }); - - tearDown(() async { - await commonServerImpl.shutdown(); - }); - - setUp(() { - log.onRecord.listen((LogRecord rec) { - print('${rec.level.name}: ${rec.time}: ${rec.message}'); - }); - }); - - tearDown(log.clearListeners); - - test('analyze Dart', () async { - final jsonData = {'source': sampleCode}; - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), {}); - }); - - test('analyze Flutter', () async { - final jsonData = {'source': sampleCodeFlutter}; - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), { - 'packageImports': ['flutter'] - }); - }); - - test('analyze code with constructor-tearoffs features', () async { - final jsonData = { - 'source': ''' -void main() { - List; -} -''' - }; - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), {}); - }); - - test('analyze counterApp', () async { - final jsonData = {'source': sampleCodeFlutterCounter}; - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), { - 'packageImports': ['flutter'] - }); - }); - - test('analyze draggableAndPhysicsApp', () async { - final jsonData = {'source': sampleCodeFlutterDraggableCard}; - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), { - 'packageImports': ['flutter'] - }); - }); - - test('analyze errors', () async { - final jsonData = {'source': sampleCodeError}; - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - expect(response.headers['content-type'], - ['application/json; charset=utf-8']); - final data = await response.transform(utf8.decoder).join(); - final dataMap = (json.decode(data) as Map).cast(); - expect( - dataMap, - { - 'issues': [ - { - 'kind': 'error', - 'line': 2, - 'sourceName': 'main.dart', - 'message': "Expected to find ';'.", - 'hasFixes': true, - 'charStart': 29, - 'charLength': 1, - 'column': 16, - 'code': 'expected_token', - } - ] - }, - ); - }); - - test('analyze negative-test noSource', () async { - final jsonData = {}; - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 400); - }); - - test('compile', () async { - final jsonData = {'source': sampleCode}; - final response = - await sendPostRequest('dartservices/v2/compile', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - test('compile with cache', () async { - final jsonData = {'source': sampleCode}; - final response1 = - await sendPostRequest('dartservices/v2/compile', jsonData); - expect(response1.statusCode, 200); - final data1 = await response1.transform(utf8.decoder).join(); - expect(json.decode(data1), isNotEmpty); - - final response2 = - await sendPostRequest('dartservices/v2/compile', jsonData); - expect(response2.statusCode, 200); - final data2 = await response2.transform(utf8.decoder).join(); - expect(json.decode(data2), isNotEmpty); - }); - - test('compile error', () async { - final jsonData = {'source': sampleCodeError}; - final response = - await sendPostRequest('dartservices/v2/compile', jsonData); - expect(response.statusCode, 400); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data, isNotEmpty); - final error = data['error'] as Map; - expect(error['message'], contains('Error: Expected')); - }); - - test('compile negative-test noSource', () async { - final jsonData = {}; - final response = - await sendPostRequest('dartservices/v2/compile', jsonData); - expect(response.statusCode, 400); - }); - - test('compileDDC', () async { - final jsonData = {'source': sampleCode}; - final response = - await sendPostRequest('dartservices/v2/compileDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - test('compileDDC with cache', () async { - final jsonData = {'source': sampleCode}; - final response1 = - await sendPostRequest('dartservices/v2/compileDDC', jsonData); - expect(response1.statusCode, 200); - final data1 = await response1.transform(utf8.decoder).join(); - expect(json.decode(data1), isNotEmpty); - - final response2 = - await sendPostRequest('dartservices/v2/compileDDC', jsonData); - expect(response2.statusCode, 200); - final data2 = await response2.transform(utf8.decoder).join(); - expect(json.decode(data2), isNotEmpty); - }); - - test('complete', () async { - final jsonData = {'source': 'void main() {print("foo");}', 'offset': 1}; - final response = - await sendPostRequest('dartservices/v2/complete', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, isNotEmpty); - }); - - test('complete no data', () async { - final response = await sendPostRequest( - 'dartservices/v2/complete', {}); - expect(response.statusCode, 400); - }); - - test('complete param missing', () async { - final jsonData = {'offset': 1}; - final response = - await sendPostRequest('dartservices/v2/complete', jsonData); - expect(response.statusCode, 400); - }); - - test('complete param missing 2', () async { - final jsonData = {'source': 'void main() {print("foo");}'}; - final response = - await sendPostRequest('dartservices/v2/complete', jsonData); - expect(response.statusCode, 400); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - final error = data['error'] as Map; - expect(error['message'], 'Missing parameter: \'offset\''); - }); - - test('document', () async { - final jsonData = {'source': 'void main() {print("foo");}', 'offset': 17}; - final response = - await sendPostRequest('dartservices/v2/document', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, isNotEmpty); - }); - - test('document little data', () async { - final jsonData = {'source': 'void main() {print("foo");}', 'offset': 2}; - final response = - await sendPostRequest('dartservices/v2/document', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, { - 'info': {}, - }); - }); - - test('document no data', () async { - final jsonData = {'source': 'void main() {print("foo");}', 'offset': 12}; - final response = - await sendPostRequest('dartservices/v2/document', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, {'info': {}}); - }); - - test('document negative-test noSource', () async { - final jsonData = {'offset': 12}; - final response = - await sendPostRequest('dartservices/v2/document', jsonData); - expect(response.statusCode, 400); - }); - - test('document negative-test noOffset', () async { - final jsonData = {'source': 'void main() {print("foo");}'}; - final response = - await sendPostRequest('dartservices/v2/document', jsonData); - expect(response.statusCode, 400); - }); - - test('format', () async { - final jsonData = {'source': preFormattedCode}; - final response = - await sendPostRequest('dartservices/v2/format', jsonData); - expect(response.statusCode, 200); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data['newString'], postFormattedCode); - }); - - test('format bad code', () async { - final jsonData = {'source': formatBadCode}; - final response = - await sendPostRequest('dartservices/v2/format', jsonData); - expect(response.statusCode, 200); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data['newString'], formatBadCode); - }); - - test('format position', () async { - final jsonData = {'source': preFormattedCode, 'offset': 21}; - final response = - await sendPostRequest('dartservices/v2/format', jsonData); - expect(response.statusCode, 200); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data['newString'], postFormattedCode); - expect(data['offset'], 24); - }); - - test('fix', () async { - final quickFixesCode = ''' -import 'dart:async'; -void main() { - int i = 0; -} -'''; - - final jsonData = {'source': quickFixesCode, 'offset': 10}; - final response = await sendPostRequest('dartservices/v2/fixes', jsonData); - expect(response.statusCode, 200); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - final fixes = data['fixes'] as List; - expect(fixes.length, 1); - final problemAndFix = fixes[0] as Map; - expect(problemAndFix['problemMessage'], isNotNull); - }); - - test('fixes completeness', () async { - final jsonData = { - 'source': ''' -void main() { - for (int i = 0; i < 4; i++) { - print('hello \$i') - } -} -''', - 'offset': 67, - }; - final response = await sendPostRequest('dartservices/v2/fixes', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, { - 'fixes': [ - { - 'fixes': [ - { - 'message': "Insert ';'", - 'edits': [ - {'offset': 67, 'length': 0, 'replacement': ';'} - ] - } - ], - 'problemMessage': "Expected to find ';'.", - 'offset': 66, - 'length': 1 - } - ] - }); - }); - - test('assist', () async { - final assistCode = ''' -main() { - int v = 0; -} -'''; - - final jsonData = {'source': assistCode, 'offset': 15}; - final response = - await sendPostRequest('dartservices/v2/assists', jsonData); - expect(response.statusCode, 200); - - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - final assists = data['assists'] as List; - expect(assists, hasLength(3)); - final firstEdit = assists.first as Map; - expect(firstEdit['edits'], isNotNull); - expect(firstEdit['edits'], hasLength(1)); - expect(assists.where((m) { - final map = m as Map; - return map['message'] == 'Remove type annotation'; - }), isNotEmpty); - }); - - test('version', () async { - final response = await sendGetRequest('dartservices/v2/version'); - expect(response.statusCode, 200); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data['sdkVersion'], isNotNull); - }); - }); - - //------------------------------------------------------------------------- - // Beginning of multi file files={} tests group: - group('CommonServerProto JSON for Multi file group files={}', () { - final sdk = Sdk(); - setUp(() async { - final cache = MockCache(); - commonServerImpl = CommonServerImpl(sdk, cache); - commonServerApi = CommonServerApi(commonServerImpl); - await commonServerImpl.init(); - - // Some piece of initialization doesn't always happen fast enough for this - // request to work in time for the test. So try it here until the server - // returns something valid. - // TODO(jcollins-g): determine which piece of initialization isn't - // happening and deal with that in warmup/init. - { - var decodedJson = {}; - final jsonData = {'source': sampleCodeError}; - while (decodedJson.isEmpty) { - final response = - await sendPostRequest('dartservices/v2/analyze', jsonData); - expect(response.statusCode, 200); - expect(response.headers['content-type'], - ['application/json; charset=utf-8']); - final data = await response.transform(utf8.decoder).join(); - decodedJson = json.decode(data) as Map; - } - } - }); - - tearDown(() async { - await commonServerImpl.shutdown(); - }); - - setUp(() { - log.onRecord.listen((LogRecord rec) { - print('${rec.level.name}: ${rec.time}: ${rec.message}'); - }); - }); - - tearDown(log.clearListeners); - - test('analyzeFiles Dart files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCode} - }; - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), {}); - }); - - test('analyzeFiles Flutter files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCodeFlutter} - }; - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), { - 'packageImports': ['flutter'] - }); - }); - - test('analyzeFiles code with constructor-tearoffs features files={}', - () async { - final jsonData = { - 'files': { - kMainDart: ''' -void main() { - List; -} -''' - } - }; - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), {}); - }); - - test('analyzeFiles counterApp files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCodeFlutterCounter} - }; - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), { - 'packageImports': ['flutter'] - }); - }); - - test('analyzeFiles draggableAndPhysicsApp files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCodeFlutterDraggableCard} - }; - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), { - 'packageImports': ['flutter'] - }); - }); - - test('analyzeFiles errors files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCodeError} - }; - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', jsonData); - expect(response.statusCode, 200); - expect(response.headers['content-type'], - ['application/json; charset=utf-8']); - final data = await response.transform(utf8.decoder).join(); - final dataMap = (json.decode(data) as Map).cast(); - expect( - dataMap, - { - 'issues': [ - { - 'kind': 'error', - 'line': 2, - 'sourceName': 'main.dart', - 'message': "Expected to find ';'.", - 'hasFixes': true, - 'charStart': 29, - 'charLength': 1, - 'column': 16, - 'code': 'expected_token', - } - ] - }, - ); - }); - - test('analyzeFiles negative-test noFiles files={}', () async { - final jsonData = {}; - final response = - await sendPostRequest('dartservices/v2/analyzeFiles', jsonData); - expect(response.statusCode, 400); - }); - - // Begin compileFiles entry point testing: - test('compileFiles files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCode} - }; - final response = - await sendPostRequest('dartservices/v2/compileFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // 2 separate files, main importing 'various.dart'. - test('compileFiles files={} with 2 files using import', () async { - final jsonData = { - 'files': { - kMainDart: sampleCodeMultiFoo, - 'bar.dart': sampleCodeMultiBar, - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // 2 separate files, main importing 'various.dart' but with - // up paths in names... test sanitizing filenames of '..\.../..' and '..' - // santizing should strip off all up dir chars and leave just the - // plain filenames. - test('compileFiles files={} with 2 files using import need sanitizing', - () async { - final jsonData = { - 'files': { - '..\\.../../$kMainDart': sampleCodeMultiFoo, - '../bar.dart': sampleCodeMultiBar - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // 2 files using "part 'bar.dart'" to bring in second file. - test('compileFiles files={} with 2 files using library/part', () async { - final jsonData = { - 'files': { - kMainDart: sampleCodeLibraryMultiFoo, - 'bar.dart': sampleCodePartMultiBar - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFiles', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - test('compileFiles with cache files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCode} - }; - final response1 = - await sendPostRequest('dartservices/v2/compileFiles', jsonData); - expect(response1.statusCode, 200); - final data1 = await response1.transform(utf8.decoder).join(); - expect(json.decode(data1), isNotEmpty); - - final response2 = - await sendPostRequest('dartservices/v2/compileFiles', jsonData); - expect(response2.statusCode, 200); - final data2 = await response2.transform(utf8.decoder).join(); - expect(json.decode(data2), isNotEmpty); - }); - - test('compileFiles error files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCodeError} - }; - final response = - await sendPostRequest('dartservices/v2/compileFiles', jsonData); - expect(response.statusCode, 400); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data, isNotEmpty); - final error = data['error'] as Map; - expect(error['message'], contains('Error: Expected')); - }); - - test('compileFiles negative-test noFiles files={}', () async { - final jsonData = {}; - final response = - await sendPostRequest('dartservices/v2/compileFiles', jsonData); - expect(response.statusCode, 400); - }); - - // Begin compileFilesDDC entry point testing DDC testing: - test('compileFilesDDC files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCode} - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // 2 separate files, main importing 'various.dart'. - test('compileFilesDDC files={} with 2 files using import', () async { - final jsonData = { - 'files': { - kMainDart: sampleCode2PartImportMain, - 'various.dart': sampleCode2PartImportVarious - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // 3 separate files, main importing 'various.dart' and 'discdata.dart'. - test('compileFilesDDC files={} with 3 files using import', () async { - final jsonData = { - 'files': { - kMainDart: sampleCode3PartImportMain, - 'discdata.dart': sampleCode3PartImportDiscData, - 'various.dart': sampleCode3PartImportVarious - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // 2 separate files, main importing 'various.dart' but with - // up paths in names... test sanitizing filenames of '..\.../..' and '..' - // santizing should strip off all up dir chars and leave just the - // plain filenames. - test('compileFilesDDC files={} with 2 files using import need sanitizing', - () async { - final jsonData = { - 'files': { - '..\\.../../$kMainDart': sampleCode2PartImportMain, - '../various.dart': sampleCode2PartImportVarious - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // 2 files using "part 'various.dart'" to bring in second file. - test('compileFilesDDC files={} with 2 files using import', () async { - final jsonData = { - 'files': { - kMainDart: sampleCode2PartImportMain, - 'various.dart': sampleCode2PartImportVarious - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // 3 files using "part 'various.dart'" and "part 'discdata.dart'" to bring - // in second and third files. - test('compileFilesDDC files={} with 3 files using import', () async { - final jsonData = { - 'files': { - kMainDart: sampleCode3PartLibraryMain, - 'discdata.dart': sampleCode3PartDiscDataPartOfTestAnim, - 'various.dart': sampleCode3PartVariousPartOfTestAnim, - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // Check sanitizing of package:, dart:, http:// from filenames. - test('compileFilesDDC files={} with 3 files using import needs sanitizing', - () async { - final jsonData = { - 'files': { - 'package:$kMainDart': sampleCode3PartLibraryMain, - 'dart:discdata.dart': sampleCode3PartDiscDataPartOfTestAnim, - 'http://various.dart': sampleCode3PartVariousPartOfTestAnim, - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - // Test renaming the file with the main function ('mymain.dart') to be - // kMainDart when no file named kMainDart is found. - test('compileFilesDDC files={} with 3 files using import', () async { - final jsonData = { - 'files': { - 'discdata.dart': sampleCode3PartDiscDataPartOfTestAnim, - 'various.dart': sampleCode3PartVariousPartOfTestAnim, - 'mymain.dart': sampleCode3PartLibraryMain - } - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 200); - final data = await response.transform(utf8.decoder).join(); - expect(json.decode(data), isNotEmpty); - }); - - test('compileFilesDDC with cache files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCode} - }; - final response1 = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response1.statusCode, 200); - final data1 = await response1.transform(utf8.decoder).join(); - expect(json.decode(data1), isNotEmpty); - - final response2 = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response2.statusCode, 200); - final data2 = await response2.transform(utf8.decoder).join(); - expect(json.decode(data2), isNotEmpty); - }); - - test('compileFilesDDC 3 files set with cache files={}', () async { - final jsonData = { - 'files': { - kMainDart: sampleCode3PartLibraryMain, - 'discdata.dart': sampleCode3PartDiscDataPartOfTestAnim, - 'various.dart': sampleCode3PartVariousPartOfTestAnim - } - }; - final response1 = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response1.statusCode, 200); - final data1 = await response1.transform(utf8.decoder).join(); - expect(json.decode(data1), isNotEmpty); - - final response2 = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response2.statusCode, 200); - final data2 = await response2.transform(utf8.decoder).join(); - expect(json.decode(data2), isNotEmpty); - }); - - test('compileFilesDDC error files={}', () async { - final jsonData = { - 'files': {kMainDart: sampleCodeError} - }; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 400); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - expect(data, isNotEmpty); - final error = data['error'] as Map; - expect(error['message'], contains('Error: Expected')); - }); - - test('compileFilesDDC negative-test noFiles files={}', () async { - final jsonData = {}; - final response = - await sendPostRequest('dartservices/v2/compileFilesDDC', jsonData); - expect(response.statusCode, 400); - }); - - test('completeFiles files={}', () async { - final jsonData = { - 'files': {kMainDart: 'void main() {print("foo");}'}, - 'activeSourceName': kMainDart, - 'offset': 1 - }; - final response = - await sendPostRequest('dartservices/v2/completeFiles', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, isNotEmpty); - }); - - test('completeFiles no data files={}', () async { - final response = await sendPostRequest( - 'dartservices/v2/completeFiles', {}); - expect(response.statusCode, 400); - }); - - test('completeFiles param missing files={}', () async { - final jsonData = {'offset': 1}; - final response = - await sendPostRequest('dartservices/v2/completeFiles', jsonData); - expect(response.statusCode, 400); - }); - - test('completeFiles param missing 2 files={}', () async { - final jsonData = { - 'files': {kMainDart: 'void main() {print("foo");}'} - }; - final response = - await sendPostRequest('dartservices/v2/completeFiles', jsonData); - expect(response.statusCode, 400); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - final error = data['error'] as Map; - expect(error['message'], 'Missing parameter: \'activeSourceName\''); - }); - - test('documentFiles files={}', () async { - final jsonData = { - 'files': {kMainDart: 'void main() {print("foo");}'}, - 'activeSourceName': kMainDart, - 'offset': 17 - }; - final response = - await sendPostRequest('dartservices/v2/documentFiles', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, isNotEmpty); - }); - - test('documentFiles little data files={}', () async { - final jsonData = { - 'files': {kMainDart: 'void main() {print("foo");}'}, - 'activeSourceName': kMainDart, - 'offset': 2 - }; - final response = - await sendPostRequest('dartservices/v2/documentFiles', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, { - 'info': {}, - }); - }); - - test('documentFiles no data files={}', () async { - final jsonData = { - 'files': {kMainDart: 'void main() {print("foo");}'}, - 'activeSourceName': kMainDart, - 'offset': 12 - }; - final response = - await sendPostRequest('dartservices/v2/documentFiles', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, {'info': {}}); - }); - - test('documentFiles negative-test noFiles files={}', () async { - final jsonData = {'offset': 12}; - final response = - await sendPostRequest('dartservices/v2/documentFiles', jsonData); - expect(response.statusCode, 400); - }); - - test('documentFiles negative-test noActiveSourceName/noOffset files={}', - () async { - final jsonData = { - 'files': {kMainDart: 'void main() {print("foo");}'} - }; - final response = - await sendPostRequest('dartservices/v2/documentFiles', jsonData); - expect(response.statusCode, 400); - }); - - test('fix2 files={}', () async { - final quickFixesCode = ''' -import 'dart:async'; -void main() { - int i = 0; -} -'''; - - final jsonData = { - 'files': {kMainDart: quickFixesCode}, - 'activeSourceName': kMainDart, - 'offset': 10 - }; - final response = - await sendPostRequest('dartservices/v2/fixesFiles', jsonData); - expect(response.statusCode, 200); - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - final fixes = data['fixes'] as List; - expect(fixes.length, 1); - final problemAndFix = fixes[0] as Map; - expect(problemAndFix['problemMessage'], isNotNull); - }); - - test('fixesFiles completeness files={}', () async { - final jsonData = { - 'files': { - kMainDart: ''' -void main() { - for (int i = 0; i < 4; i++) { - print('hello \$i') - } -} -''' - }, - 'activeSourceName': kMainDart, - 'offset': 67, - }; - final response = - await sendPostRequest('dartservices/v2/fixesFiles', jsonData); - expect(response.statusCode, 200); - final data = json.decode(await response.transform(utf8.decoder).join()); - expect(data, { - 'fixes': [ - { - 'fixes': [ - { - 'message': "Insert ';'", - 'edits': [ - {'offset': 67, 'length': 0, 'replacement': ';'} - ] - } - ], - 'problemMessage': "Expected to find ';'.", - 'offset': 66, - 'length': 1 - } - ] - }); - }); - - test('assist2 files={}', () async { - final assistCode = ''' -main() { - int v = 0; -} -'''; - - final jsonData = { - 'files': {kMainDart: assistCode}, - 'activeSourceName': kMainDart, - 'offset': 15 - }; - final response = - await sendPostRequest('dartservices/v2/assistsFiles', jsonData); - expect(response.statusCode, 200); - - final encoded = await response.transform(utf8.decoder).join(); - final data = json.decode(encoded) as Map; - final assists = data['assists'] as List; - expect(assists, hasLength(3)); - final firstEdit = assists.first as Map; - expect(firstEdit['edits'], isNotNull); - expect(firstEdit['edits'], hasLength(1)); - expect(assists.where((m) { - final map = m as Map; - return map['message'] == 'Remove type annotation'; - }), isNotEmpty); - }); - }); - // End of multi file files={} tests group. - //------------------------------------------------------------------------- -} diff --git a/pkgs/dart_services/test/common_test.dart b/pkgs/dart_services/test/common_test.dart deleted file mode 100644 index 0669f85fa..000000000 --- a/pkgs/dart_services/test/common_test.dart +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file -// 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. - -// ignore_for_file: prefer_single_quotes - -import 'package:dart_services/src/common.dart'; -import 'package:test/test.dart'; - -void main() => defineTests(); - -void defineTests() { - test('countLines', () { - final sources = { - 'file1': '\n\n\n\n\n', // 5 lines, - 'file2': r'''THis is line 1, - This is line 2, - THis is line 3''', // 3 lines, - 'file3': 'line1\r\nline2\r\nline 3\r\n', // 3 lines, - 'file4': 'line1\nline2\nline3\n', // 3 lines, - 'file5': 'line1\rline2\rline3\r', // and 3 lines makes 17 total lines. - }; - expect(countLines(sources), 17); - }); - - test('countEOLsInString', () { - expect(countLinesInString('line1\r\nline2\r\nline 3\r\n\r\n'), 4); - expect(countLinesInString('line1\nline2\nline3\nline4\n\n'), 5); - expect(countLinesInString('line1\rline2\rline3\rline4\rline5\r\r'), 6); - expect(countLinesInString('\n\n\n\n\n\n\n'), 7); - expect(countLinesInString('\r\r\r\r\r\r\r\r'), 8); - expect(countLinesInString('\n\n\n\n\n\n\n\n\n'), 9); - expect(countLinesInString(r'''THis is line 1, - This is line 2 -'''), 2); - }); - - test('sanitizeAndCheckFilenames', () { - final filesSanitize = { - '..\\.../../$kMainDart': '', - '../various.dart': '' - }; - - sanitizeAndCheckFilenames(filesSanitize); - expect(filesSanitize.keys.elementAt(0), kMainDart); - expect(filesSanitize.keys.elementAt(1), 'various.dart'); - - // Using "part 'various.dart'" to bring in second file. - final filesVar2 = { - 'mymain.dart': 'void main() => ();', - 'various.dart': '', - 'discdata.dart': '' - }; - - var newmain = sanitizeAndCheckFilenames(filesVar2, 'mymain.dart'); - expect(newmain, kMainDart); - expect(filesVar2.keys.elementAt(0), kMainDart); - expect(filesVar2.keys.elementAt(1), 'various.dart'); - - final filesVar3Sani = { - 'package:$kMainDart': '', - 'dart:discdata.dart': '', - 'http://dart:http://various.dart': '' - }; - newmain = sanitizeAndCheckFilenames(filesVar3Sani, 'package:$kMainDart'); - expect(newmain, kMainDart); - expect(filesVar3Sani.keys.elementAt(0), kMainDart); - expect(filesVar3Sani.keys.elementAt(1), 'discdata.dart'); - expect(filesVar3Sani.keys.elementAt(2), 'various.dart'); - }); -} diff --git a/pkgs/dart_services/test/compiler_test.dart b/pkgs/dart_services/test/compiler_test.dart deleted file mode 100644 index 1763cf517..000000000 --- a/pkgs/dart_services/test/compiler_test.dart +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file -// 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 'package:dart_services/src/common.dart'; -import 'package:dart_services/src/compiler.dart'; -import 'package:dart_services/src/sdk.dart'; -import 'package:test/test.dart'; - -void main() => defineTests(); - -void defineTests() { - const kMainDart = 'main.dart'; - - group('(Always) Null Safe Compiler', () { - late Compiler compiler; - - setUpAll(() async { - compiler = Compiler(Sdk(), storageBucket: 'nnbd_artifacts'); - await compiler.warmup(); - }); - - tearDownAll(() async { - await compiler.dispose(); - }); - - Future Function() generateCompilerFilesTest( - Map files) => - () async { - final result = - await compiler.compileFiles(files, returnSourceMap: false); - expect(result.problems, isEmpty); - expect(result.success, true); - expect(result.compiledJS, isNotEmpty); - - expect(result.compiledJS, contains('(function dartProgram() {')); - }; - - Future Function() generateCompilerFilesDDCTest( - Map files) => - () async { - final result = await compiler.compileFilesDDC(files); - expect(result.problems, isEmpty); - expect(result.success, true); - expect(result.compiledJS, isNotEmpty); - expect(result.modulesBaseUrl, isNotEmpty); - - expect(result.compiledJS, contains("define('dartpad_main', [")); - }; - - Future Function() generateCompilerDDCTest(String sample) => () async { - final result = await compiler.compileDDC(sample); - expect(result.problems, isEmpty); - expect(result.success, true); - expect(result.compiledJS, isNotEmpty); - expect(result.modulesBaseUrl, isNotEmpty); - - expect(result.compiledJS, contains("define('dartpad_main', [")); - }; - - test('simple', () async { - final result = await compiler.compile(sampleCode); - - expect(result.problems, isEmpty); - expect(result.success, true); - expect(result.compiledJS, isNotEmpty); - expect(result.sourceMap, isNull); - }); - - test( - 'compileDDC simple', - generateCompilerDDCTest(sampleCode), - ); - - test( - 'compileDDC with web', - generateCompilerDDCTest(sampleCodeWeb), - ); - - test( - 'compileDDC with Flutter', - generateCompilerDDCTest(sampleCodeFlutter), - ); - - test( - 'compileDDC with Flutter Counter', - generateCompilerDDCTest(sampleCodeFlutterCounter), - ); - - test( - 'compileDDC with Flutter Sunflower', - generateCompilerDDCTest(sampleCodeFlutterSunflower), - ); - - test( - 'compileDDC with Flutter Draggable Card', - generateCompilerDDCTest(sampleCodeFlutterDraggableCard), - ); - - test( - 'compileDDC with Flutter Implicit Animations', - generateCompilerDDCTest(sampleCodeFlutterImplicitAnimations), - ); - - test( - 'compileDDC with async', - generateCompilerDDCTest(sampleCodeAsync), - ); - - test('compileDDC with single error', () async { - final result = await compiler.compileDDC(sampleCodeError); - expect(result.success, false); - expect(result.problems.length, 1); - expect(result.problems[0].toString(), - contains('Error: Expected \';\' after this.')); - }); - - test('compileDDC with multiple errors', () async { - final result = await compiler.compileDDC(sampleCodeErrors); - expect(result.success, false); - expect(result.problems.length, 1); - expect(result.problems[0].toString(), - contains('Error: Method not found: \'print1\'.')); - expect(result.problems[0].toString(), - contains('Error: Method not found: \'print2\'.')); - expect(result.problems[0].toString(), - contains('Error: Method not found: \'print3\'.')); - }); - - test('sourcemap', () async { - final result = await compiler.compile(sampleCode, returnSourceMap: true); - expect(result.success, true); - expect(result.compiledJS, isNotEmpty); - expect(result.sourceMap, isNotNull); - expect(result.sourceMap, isNotEmpty); - }); - - test('version', () async { - final result = await compiler.compile(sampleCode, returnSourceMap: true); - expect(result.sourceMap, isNotNull); - expect(result.sourceMap, isNotEmpty); - }); - - test('simple web', () async { - final result = await compiler.compile(sampleCodeWeb); - expect(result.success, true); - }); - - test('web async', () async { - final result = await compiler.compile(sampleCodeAsync); - expect(result.success, true); - }); - - test('errors', () async { - final result = await compiler.compile(sampleCodeError); - expect(result.success, false); - expect(result.problems.length, 1); - expect(result.problems[0].toString(), contains('Error: Expected')); - }); - - test('good import', () async { - const code = ''' -import 'dart:html'; - -void main() { - var count = querySelector('#count'); - print('hello'); -} - -'''; - final result = await compiler.compile(code); - expect(result.problems.length, 0); - }); - - test('good import - empty', () async { - const code = ''' -import '' as foo; - -int bar = 2; - -void main() { - print(foo.bar); -} - -'''; - final result = await compiler.compile(code); - expect(result.problems.length, 0); - }); - - test('bad import - local', () async { - const code = ''' -import 'foo.dart'; -void main() { missingMethod ('foo'); } -'''; - final result = await compiler.compile(code); - expect(result.problems, hasLength(1)); - expect(result.problems.single.message, - equals('unsupported import: foo.dart')); - }); - - test('bad import - http', () async { - const code = ''' -import 'http://example.com'; -void main() { missingMethod ('foo'); } -'''; - final result = await compiler.compile(code); - expect(result.problems, hasLength(1)); - expect(result.problems.single.message, - equals('unsupported import: http://example.com')); - }); - - test('multiple bad imports', () async { - const code = ''' -import 'package:foo'; -import 'package:bar'; -'''; - final result = await compiler.compile(code); - expect(result.problems, hasLength(2)); - expect(result.problems[0].message, - equals('unsupported import: package:foo')); - expect(result.problems[1].message, - equals('unsupported import: package:bar')); - }); - - test('disallow compiler warnings', () async { - final result = await compiler.compile(sampleCodeErrors); - expect(result.success, false); - }); - - test('transitive errors', () async { - const code = ''' -import 'dart:foo'; -void main() { print ('foo'); } -'''; - final result = await compiler.compile(code); - expect(result.problems.length, 1); - }); - - //--------------------------------------------------------------- - // Beginning of multi file files={} tests group: - - test( - 'files:{} compileFilesDDC simple', - generateCompilerFilesDDCTest({kMainDart: sampleCode}), - ); - - test( - 'files:{} compileFilesDDC with web', - generateCompilerFilesDDCTest({kMainDart: sampleCodeWeb}), - ); - - // Try not using 'main.dart' filename, should be handled OK. - test( - 'files:{} compileFilesDDC with Flutter', - generateCompilerFilesDDCTest({'mymainthing.dart': sampleCodeFlutter}), - ); - - // Filename other than 'main.dart'. - test( - 'files:{} no main.dart (different.dart) compileFilesDDC with Flutter Counter', - generateCompilerFilesDDCTest( - {'different.dart': sampleCodeFlutterCounter}), - ); - - // 2 separate files, main importing 'various.dart'. - test( - 'files:{} compileFilesDDC with 2 files using import', - generateCompilerFilesDDCTest({ - kMainDart: sampleCode2PartImportMain, - 'various.dart': sampleCode2PartImportVarious - }), - ); - - // 3 separate files, main importing 'various.dart' and 'discdata.dart', - // and 'various.dart' importing 'discdata.dart'. - test( - 'files:{} compileFilesDDC with 3 file using imports', - generateCompilerFilesDDCTest({ - kMainDart: sampleCode3PartImportMain, - 'discdata.dart': sampleCode3PartImportDiscData, - 'various.dart': sampleCode3PartImportVarious - }), - ); - - // 2 separate files, main importing 'various.dart' but with - // up paths in names...test sanitizing filenames of '..\.../..' and '..' - // santizing should strip off all up dir chars and leave just the - // plain filenames. - test( - 'files:{} compileFilesDDC with 2 files and file names sanitized', - generateCompilerFilesDDCTest({ - '..\\.../../$kMainDart': sampleCode2PartImportMain, - '../various.dart': sampleCode2PartImportVarious - }), - ); - - // 2 files using "part 'various.dart'" to bring in second file. - test( - 'files:{} compileFilesDDC with 2 file using LIBRARY/PART/PART OF', - generateCompilerFilesDDCTest({ - kMainDart: sampleCode2PartLibraryMain, - 'various.dart': sampleCode2PartVariousAndDiscDataPartOfTestAnim - }), - ); - - // 3 files using "part 'various.dart'" and "part 'discdata.dart'" to bring - // in second and third files. - test( - 'files:{} compileFilesDDC with 3 files using LIBRARY/PART/PART OF', - generateCompilerFilesDDCTest({ - kMainDart: sampleCode3PartLibraryMain, - 'discdata.dart': sampleCode3PartDiscDataPartOfTestAnim, - 'various.dart': sampleCode3PartVariousPartOfTestAnim - }), - ); - - // Check sanitizing of package:, dart:, http:// from filenames. - test( - 'files:{} compileFilesDDC with 3 SANITIZED files using LIBRARY/PART/PART OF', - generateCompilerFilesDDCTest({ - 'package:$kMainDart': sampleCode3PartLibraryMain, - 'dart:discdata.dart': sampleCode3PartDiscDataPartOfTestAnim, - 'http://various.dart': sampleCode3PartVariousPartOfTestAnim - }), - ); - - // Test renaming the file with the main function ('mymain.dart') to be - // kMainDart when no file named kMainDart is found. - test( - 'files:{} compileFilesDDC with 3 files and none named kMainDart', - generateCompilerFilesDDCTest({ - 'discdata.dart': sampleCode3PartDiscDataPartOfTestAnim, - 'various.dart': sampleCode3PartVariousPartOfTestAnim, - 'mymain.dart': sampleCode3PartLibraryMain - }), - ); - - // Two separate files, illegal import in second file, test that - // illegal imports within all files are detected. - final filesVar2BadImports = {}; - const badImports = ''' -import 'package:foo'; -import 'package:bar'; - '''; - filesVar2BadImports[kMainDart] = ''' -$sampleCode3PartFlutterImplicitAnimationsImports -import 'various.dart'; -$sampleCode3PartFlutterImplicitAnimationsMain - '''; - filesVar2BadImports['various.dart'] = ''' -$sampleCode3PartFlutterImplicitAnimationsImports -$badImports -$sampleCode3PartFlutterImplicitAnimationsDiscData -$sampleCode3PartFlutterImplicitAnimationsVarious - '''; - test('multiple files, second file with multiple bad imports compileFiles()', - () async { - final result = await compiler.compileFiles(filesVar2BadImports); - expect(result.problems, hasLength(2)); - expect(result.problems[0].message, - equals('unsupported import: package:foo')); - expect(result.problems[1].message, - equals('unsupported import: package:bar')); - }); - test( - 'multiple files, second file with multiple bad imports compileFilesDDC()', - () async { - final result = await compiler.compileFilesDDC(filesVar2BadImports); - expect(result.problems, hasLength(2)); - expect(result.problems[0].message, - equals('unsupported import: package:foo')); - expect(result.problems[1].message, - equals('unsupported import: package:bar')); - }); - - //------------------------------------------------------------------ - // Similiar test as above but targeting compileFiles(): - test( - 'files:{} compileFiles simple', - generateCompilerFilesTest({kMainDart: sampleCode}), - ); - - test( - 'files:{} compileFiles with web', - generateCompilerFilesTest({kMainDart: sampleCodeWeb}), - ); - - // 2 separate files, main importing 'various.dart'. - test( - 'files:{} compileFiles with 2 file', - generateCompilerFilesTest( - {kMainDart: sampleCodeMultiFoo, 'bar.dart': sampleCodeMultiBar}), - ); - - // 2 separate files, main importing 'various.dart' but with - // up paths in names...test sanitizing filenames of '..\.../..' and '..' - // santizing should strip off all up dir chars and leave just the - // plain filenames. - test( - 'files:{} compileFiles with 2 files and file names sanitized', - generateCompilerFilesTest({ - '..\\.../../$kMainDart': sampleCodeMultiFoo, - '../bar.dart': sampleCodeMultiBar - }), - ); - - // Using "part 'various.dart'" to bring in second file. - test( - 'files:{} compileFiles with 2 file using LIBRARY/PART/PART OF', - generateCompilerFilesTest({ - kMainDart: sampleCodeLibraryMultiFoo, - 'bar.dart': sampleCodePartMultiBar - }), - ); - - // Check sanitizing of package:, dart:, http:// from filenames. - test( - 'files:{} compileFiles with 2 sanitized files using LIBRARY/PART/PART OF', - generateCompilerFilesTest({ - 'package:$kMainDart': sampleCodeLibraryMultiFoo, - 'dart:bar.dart': sampleCodePartMultiBar - }), - ); - - // Test renaming the file with the main function ('mymain.dart') to be - // kMainDart when no file named kMainDat is found. - test( - 'files:{} compileFiles with 2 files and none named kMainDart', - generateCompilerFilesTest( - {'mymain.dart': sampleCodeMultiFoo, 'bar.dart': sampleCodeMultiBar}), - ); - // End of multi file files={} map testing. - }); -} diff --git a/pkgs/dart_services/test/compiling_test.dart b/pkgs/dart_services/test/compiling_test.dart new file mode 100644 index 000000000..8f51bbb2c --- /dev/null +++ b/pkgs/dart_services/test/compiling_test.dart @@ -0,0 +1,216 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// 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 'package:dart_services/src/compiling.dart'; +import 'package:dart_services/src/sdk.dart'; +import 'package:test/test.dart'; + +import 'src/sample_code.dart'; + +void main() => defineTests(); + +void defineTests() { + group('compiling', () { + late Compiler compiler; + + setUpAll(() async { + compiler = Compiler(Sdk(), storageBucket: 'nnbd_artifacts'); + await compiler.warmup(); + }); + + tearDownAll(() async { + await compiler.dispose(); + }); + + Future Function() generateCompilerDDCTest(String sample) { + return () async { + final result = await compiler.compileDDC(sample); + expect(result.problems, isEmpty); + expect(result.success, true); + expect(result.compiledJS, isNotEmpty); + expect(result.modulesBaseUrl, isNotEmpty); + + expect(result.compiledJS, contains("define('dartpad_main', [")); + }; + } + + test('simple', () async { + final result = await compiler.compile(sampleCode); + + expect(result.problems, isEmpty); + expect(result.success, true); + expect(result.compiledJS, isNotEmpty); + expect(result.sourceMap, isNull); + }); + + test( + 'compileDDC simple', + generateCompilerDDCTest(sampleCode), + ); + + test( + 'compileDDC with web', + generateCompilerDDCTest(sampleCodeWeb), + ); + + test( + 'compileDDC with Flutter', + generateCompilerDDCTest(sampleCodeFlutter), + ); + + test( + 'compileDDC with Flutter Counter', + generateCompilerDDCTest(sampleCodeFlutterCounter), + ); + + test( + 'compileDDC with Flutter Sunflower', + generateCompilerDDCTest(sampleCodeFlutterSunflower), + ); + + test( + 'compileDDC with Flutter Draggable Card', + generateCompilerDDCTest(sampleCodeFlutterDraggableCard), + ); + + test( + 'compileDDC with Flutter Implicit Animations', + generateCompilerDDCTest(sampleCodeFlutterImplicitAnimations), + ); + + test( + 'compileDDC with async', + generateCompilerDDCTest(sampleCodeAsync), + ); + + test('compileDDC with single error', () async { + final result = await compiler.compileDDC(sampleCodeError); + expect(result.success, false); + expect(result.problems.length, 1); + expect(result.problems[0].toString(), + contains('Error: Expected \';\' after this.')); + }); + + test('compileDDC with multiple errors', () async { + final result = await compiler.compileDDC(sampleCodeErrors); + expect(result.success, false); + expect(result.problems.length, 1); + expect(result.problems[0].toString(), + contains('Error: Method not found: \'print1\'.')); + expect(result.problems[0].toString(), + contains('Error: Method not found: \'print2\'.')); + expect(result.problems[0].toString(), + contains('Error: Method not found: \'print3\'.')); + }); + + test('sourcemap', () async { + final result = await compiler.compile(sampleCode, returnSourceMap: true); + expect(result.success, true); + expect(result.compiledJS, isNotEmpty); + expect(result.sourceMap, isNotNull); + expect(result.sourceMap, isNotEmpty); + }); + + test('version', () async { + final result = await compiler.compile(sampleCode, returnSourceMap: true); + expect(result.sourceMap, isNotNull); + expect(result.sourceMap, isNotEmpty); + }); + + test('simple web', () async { + final result = await compiler.compile(sampleCodeWeb); + expect(result.success, true); + }); + + test('web async', () async { + final result = await compiler.compile(sampleCodeAsync); + expect(result.success, true); + }); + + test('errors', () async { + final result = await compiler.compile(sampleCodeError); + expect(result.success, false); + expect(result.problems.length, 1); + expect(result.problems[0].toString(), contains('Error: Expected')); + }); + + test('good import', () async { + const code = ''' +import 'dart:html'; + +void main() { + var count = querySelector('#count'); + print('hello'); +} + +'''; + final result = await compiler.compile(code); + expect(result.problems.length, 0); + }); + + test('good import - empty', () async { + const code = ''' +import '' as foo; + +int bar = 2; + +void main() { + print(foo.bar); +} + +'''; + final result = await compiler.compile(code); + expect(result.problems.length, 0); + }); + + test('bad import - local', () async { + const code = ''' +import 'foo.dart'; +void main() { missingMethod ('foo'); } +'''; + final result = await compiler.compile(code); + expect(result.problems, hasLength(1)); + expect(result.problems.single.message, + equals('unsupported import: foo.dart')); + }); + + test('bad import - http', () async { + const code = ''' +import 'http://example.com'; +void main() { missingMethod ('foo'); } +'''; + final result = await compiler.compile(code); + expect(result.problems, hasLength(1)); + expect(result.problems.single.message, + equals('unsupported import: http://example.com')); + }); + + test('multiple bad imports', () async { + const code = ''' +import 'package:foo'; +import 'package:bar'; +'''; + final result = await compiler.compile(code); + expect(result.problems, hasLength(2)); + expect(result.problems[0].message, + equals('unsupported import: package:foo')); + expect(result.problems[1].message, + equals('unsupported import: package:bar')); + }); + + test('disallow compiler warnings', () async { + final result = await compiler.compile(sampleCodeErrors); + expect(result.success, false); + }); + + test('transitive errors', () async { + const code = ''' +import 'dart:foo'; +void main() { print ('foo'); } +'''; + final result = await compiler.compile(code); + expect(result.problems.length, 1); + }); + }); +} diff --git a/pkgs/dart_services/test/flutter_analysis_server_test.dart b/pkgs/dart_services/test/flutter_analysis_server_test.dart deleted file mode 100644 index 3f503db43..000000000 --- a/pkgs/dart_services/test/flutter_analysis_server_test.dart +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file -// 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:io'; - -import 'package:dart_services/src/analysis_server.dart'; -import 'package:dart_services/src/analyzer_wrapper.dart'; -import 'package:dart_services/src/common.dart'; -import 'package:dart_services/src/common_server_impl.dart'; -import 'package:dart_services/src/protos/dart_services.pbserver.dart'; -import 'package:dart_services/src/sdk.dart'; -import 'package:dart_services/src/server_cache.dart'; -import 'package:test/test.dart'; - -final channel = Platform.environment['FLUTTER_CHANNEL'] ?? 'stable'; - -void main() => defineTests(); - -void defineTests() { - group('Flutter SDK analysis_server', () { - late AnalysisServerWrapper analysisServer; - - setUp(() async { - final sdk = Sdk(); - analysisServer = DartAnalysisServerWrapper(dartSdkPath: sdk.dartSdkPath); - await analysisServer.init(); - }); - - tearDown(() async { - await analysisServer.shutdown(); - }); - - test('analyze counter app', () async { - final results = await analysisServer.analyze(sampleCodeFlutterCounter); - expect(results.issues, isEmpty); - }); - - test('analyze Draggable Physics sample', () async { - final results = - await analysisServer.analyze(sampleCodeFlutterDraggableCard); - expect(results.issues, isEmpty); - }); - }); - - group( - 'Flutter SDK analysis_server with analysis ' - 'servers', () { - late AnalyzerWrapper analysisServersWrapper; - late Sdk sdk; - setUp(() async { - sdk = Sdk(); - analysisServersWrapper = AnalyzerWrapper(sdk.dartSdkPath); - await analysisServersWrapper.init(); - }); - - tearDown(() async { - await analysisServersWrapper.shutdown(); - }); - - test('reports errors with Flutter code', () async { - late AnalysisResults results; - results = await analysisServersWrapper.analyze(''' -import 'package:flutter/material.dart'; - -String x = 7; - -void main() async { - runApp(MaterialApp( - debugShowCheckedModeBanner: false, home: Scaffold(body: HelloWorld()))); -} - -class HelloWorld extends StatelessWidget { - @override - Widget build(context) => const Center(child: Text('Hello world')); -} -'''); - expect(results.issues, hasLength(1)); - final issue = results.issues[0]; - expect(issue.line, 3); - expect(issue.kind, 'error'); - expect( - issue.message, - "A value of type 'int' can't be assigned to a variable of type " - "'String'."); - }); - - // https://github.com/dart-lang/dart-pad/issues/2005 - test('reports lint with Flutter code', () async { - late AnalysisResults results; - results = await analysisServersWrapper.analyze(''' -import 'package:flutter/material.dart'; - -void main() async { - var unknown; - print(unknown); - - runApp(MaterialApp( - debugShowCheckedModeBanner: false, home: Scaffold(body: HelloWorld()))); -} - -class HelloWorld extends StatelessWidget { - @override - Widget build(context) => const Center(child: Text('Hello world')); -} -'''); - expect(results.issues, hasLength(1)); - final issue = results.issues[0]; - expect(issue.line, 4); - expect(issue.kind, 'info'); - expect(issue.message, - 'An uninitialized variable should have an explicit type annotation.'); - }); - - test('analyze counter app', () async { - final results = - await analysisServersWrapper.analyze(sampleCodeFlutterCounter); - expect(results.issues, isEmpty); - }); - - test('analyze Draggable Physics sample', () async { - final results = - await analysisServersWrapper.analyze(sampleCodeFlutterDraggableCard); - expect(results.issues, isEmpty); - }); - - test('analyze counter app', () async { - final results = - await analysisServersWrapper.analyze(sampleCodeFlutterCounter); - expect(results.issues, isEmpty); - }); - - test('analyze Draggable Physics sample', () async { - final results = - await analysisServersWrapper.analyze(sampleCodeFlutterDraggableCard); - expect(results.issues, isEmpty); - }); - }); - - group('CommonServerImpl flutter analyze', () { - late CommonServerImpl commonServerImpl; - - _MockCache cache; - - setUp(() async { - cache = _MockCache(); - final sdk = Sdk(); - commonServerImpl = CommonServerImpl(sdk, cache); - await commonServerImpl.init(); - }); - - tearDown(() async { - await commonServerImpl.shutdown(); - }); - - test('counter app', () async { - final results = await commonServerImpl - .analyze(SourceRequest()..source = sampleCodeFlutterCounter); - expect(results.issues, isEmpty); - }); - - test('Draggable Physics sample', () async { - final results = await commonServerImpl - .analyze(SourceRequest()..source = sampleCodeFlutterDraggableCard); - expect(results.issues, isEmpty); - }); - }); - - ///---------------------------------------------------------------- - /// Beginning of multi file files={} tests group: - group('MULTI FILE files={} Tests', () { - group('Flutter SDK analysis_server files={} variation', () { - late AnalysisServerWrapper analysisServer; - - setUp(() async { - final sdk = Sdk(); - analysisServer = - DartAnalysisServerWrapper(dartSdkPath: sdk.dartSdkPath); - await analysisServer.init(); - }); - - tearDown(() async { - await analysisServer.shutdown(); - }); - - test('analyzeFiles counter app files={}', () async { - final results = await analysisServer - .analyzeFiles({kMainDart: sampleCodeFlutterCounter}); - expect(results.issues, isEmpty); - }); - - test('analyzeFiles Draggable Physics sample files={}', () async { - final results = await analysisServer - .analyzeFiles({kMainDart: sampleCodeFlutterDraggableCard}); - expect(results.issues, isEmpty); - }); - }); - - group( - 'Flutter SDK analysis_server with analysis files={}' - 'servers', () { - late AnalyzerWrapper analysisServersWrapper; - late Sdk sdk; - setUp(() async { - sdk = Sdk(); - analysisServersWrapper = AnalyzerWrapper(sdk.dartSdkPath); - await analysisServersWrapper.init(); - }); - - tearDown(() async { - await analysisServersWrapper.shutdown(); - }); - - test('reports errors with Flutter code files={}', () async { - late AnalysisResults results; - results = await analysisServersWrapper.analyzeFiles({ - kMainDart: ''' -import 'package:flutter/material.dart'; - -String x = 7; - -void main() async { - runApp(MaterialApp( - debugShowCheckedModeBanner: false, home: Scaffold(body: HelloWorld()))); -} - -class HelloWorld extends StatelessWidget { - @override - Widget build(context) => const Center(child: Text('Hello world')); -} -''' - }, kMainDart); - expect(results.issues, hasLength(1)); - final issue = results.issues[0]; - expect(issue.line, 3); - expect(issue.kind, 'error'); - expect( - issue.message, - "A value of type 'int' can't be assigned to a variable of type " - "'String'."); - }); - - // https://github.com/dart-lang/dart-pad/issues/2005 - test('reports lint with Flutter code files={}', () async { - late AnalysisResults results; - results = await analysisServersWrapper.analyzeFiles({ - kMainDart: ''' -import 'package:flutter/material.dart'; - -void main() async { - var unknown; - print(unknown); - - runApp(MaterialApp( - debugShowCheckedModeBanner: false, home: Scaffold(body: HelloWorld()))); -} - -class HelloWorld extends StatelessWidget { - @override - Widget build(context) => const Center(child: Text('Hello world')); -} -''' - }, kMainDart); - expect(results.issues, hasLength(1)); - final issue = results.issues[0]; - expect(issue.line, 4); - expect(issue.kind, 'info'); - expect(issue.message, - 'An uninitialized variable should have an explicit type annotation.'); - }); - - test('analyzeFiles counter app files={}', () async { - final results = await analysisServersWrapper - .analyzeFiles({kMainDart: sampleCodeFlutterCounter}, kMainDart); - expect(results.issues, isEmpty); - }); - - test('analyzeFiles Draggable Physics sample files={}', () async { - final results = await analysisServersWrapper.analyzeFiles( - {kMainDart: sampleCodeFlutterDraggableCard}, kMainDart); - expect(results.issues, isEmpty); - }); - - test('analyzeFiles counter app files={}', () async { - final results = await analysisServersWrapper - .analyzeFiles({kMainDart: sampleCodeFlutterCounter}, kMainDart); - expect(results.issues, isEmpty); - }); - - test('analyzeFiles Draggable Physics sample files={}', () async { - final results = await analysisServersWrapper.analyzeFiles( - {kMainDart: sampleCodeFlutterDraggableCard}, kMainDart); - expect(results.issues, isEmpty); - }); - }); - - group('CommonServerImpl flutter analyzeFiles files={}', () { - late CommonServerImpl commonServerImpl; - - _MockCache cache; - - setUp(() async { - cache = _MockCache(); - final sdk = Sdk(); - commonServerImpl = CommonServerImpl(sdk, cache); - await commonServerImpl.init(); - }); - - tearDown(() async { - await commonServerImpl.shutdown(); - }); - - test('counter app files={}', () async { - final results = await commonServerImpl.analyzeFiles(SourceFilesRequest() - ..files.addAll({kMainDart: sampleCodeFlutterCounter}) - ..activeSourceName = kMainDart - ..offset = 0); - expect(results.issues, isEmpty); - }); - - test('Draggable Physics sample files={}', () async { - final results = await commonServerImpl.analyzeFiles(SourceFilesRequest() - ..files.addAll({kMainDart: sampleCodeFlutterDraggableCard}) - ..activeSourceName = kMainDart); - expect(results.issues, isEmpty); - }); - }); - }); -} - -class _MockCache implements ServerCache { - @override - Future get(String key) => Future.value(null); - - @override - Future set(String key, String value, {Duration? expiration}) => - Future.value(); - - @override - Future remove(String key) => Future.value(); - - @override - Future shutdown() => Future.value(); -} diff --git a/pkgs/dart_services/test/flutter_web_test.dart b/pkgs/dart_services/test/flutter_web_test.dart index 534e5ff28..d80a83d86 100644 --- a/pkgs/dart_services/test/flutter_web_test.dart +++ b/pkgs/dart_services/test/flutter_web_test.dart @@ -6,7 +6,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:analyzer/dart/ast/ast.dart'; -import 'package:dart_services/src/project.dart'; +import 'package:dart_services/src/project_templates.dart'; import 'package:path/path.dart' as path; import 'package:test/test.dart'; @@ -72,7 +72,7 @@ void defineTests() { }); }); - group('project initializes', () { + group('flutter web project', () { test('packagesFilePath', () async { final packageConfig = File(path.join( projectTemplates.flutterPath, '.dart_tool', 'package_config.json')); diff --git a/pkgs/dart_services/test/gae_deployed_test.dart b/pkgs/dart_services/test/gae_deployed_test.dart deleted file mode 100644 index 5800f6a83..000000000 --- a/pkgs/dart_services/test/gae_deployed_test.dart +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file -// 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 'package:dart_services/src/common.dart' as common; -import 'package:http/http.dart' as http; -import 'package:test/test.dart'; - -final String serverUrl = 'https://liftoff-dev.appspot.com'; - -void main() => defineTests(); - -void defineTests({bool skip = true}) { - group('gae deployed tests', () { - test('analyze end point', analyzeTest, skip: skip); - test('compile end point', compileTest, skip: skip); - test('compileDDC end point', compileDDCTest, skip: skip); - }); -} - -void analyzeTest() { - final url = Uri.parse('$serverUrl/api/analyze'); - final headers = {'Content-Type': 'text/plain; charset=UTF-8'}; - - expect( - http - .post(url, headers: headers, body: common.sampleCodeWeb) - .then((response) { - expect(response.statusCode, 200); - expect(response.body.trim(), '[]'); - return true; - }), - completion(equals(true))); -} - -void compileTest() { - final url = Uri.parse('$serverUrl/api/compile'); - final headers = {'Content-Type': 'text/plain; charset=UTF-8'}; - - expect( - http - .post(url, headers: headers, body: common.sampleCodeWeb) - .then((response) { - expect(response.statusCode, 200); - expect(true, response.body.length > 100); - return true; - }), - completion(equals(true))); -} - -void compileDDCTest() { - final url = Uri.parse('$serverUrl/api/compileDDC'); - final headers = {'Content-Type': 'text/plain; charset=UTF-8'}; - - expect( - http - .post(url, headers: headers, body: common.sampleCodeWeb) - .then((response) { - expect(response.statusCode, 200); - expect(true, response.body.length > 100); - return true; - }), - completion(equals(true))); -} diff --git a/pkgs/dart_services/test/project_creator_test.dart b/pkgs/dart_services/test/project_creator_test.dart index 627e9589f..eb41525b7 100644 --- a/pkgs/dart_services/test/project_creator_test.dart +++ b/pkgs/dart_services/test/project_creator_test.dart @@ -9,10 +9,11 @@ import 'package:test_descriptor/test_descriptor.dart' as d; void main() => defineTests(); -final sdk = Sdk(); -String get languageVersion => sdk.dartVersion; - void defineTests() { + final sdk = Sdk(); + + final languageVersion = sdk.dartVersion; + Future projectCreator() async { final dependenciesFile = d.file('dependencies.json', ''' { @@ -27,199 +28,201 @@ void defineTests() { templatesPath.io.path, dartLanguageVersion: sdk.dartVersion, dependenciesFile: dependenciesFile.io, - log: (_) {}, + log: printOnFailure, ); } - group('basic dart project template', () { - setUpAll(() async { - await (await projectCreator()).buildDartProjectTemplate(); - }); - - test('project directory is created', () async { - await d.dir('project_templates', [ - d.dir('dart_project'), - ]).validate(); - }); - - test('pubspec is created', () async { - await d.dir('project_templates', [ - d.dir('dart_project', [ - d.file( - 'pubspec.yaml', - allOf([ - contains('sdk: ^$languageVersion'), - ]), - ), - ]), - ]).validate(); - }); - - test('pub get creates pubspec.lock', () async { - await d.dir('project_templates', [ - d.dir('dart_project', [d.file('pubspec.lock', isNotEmpty)]), - ]).validate(); - }); - - test('recommended lints are enabled', () async { - await d.dir('project_templates', [ - d.dir('dart_project', [ - d.file( - 'analysis_options.yaml', - matches('include: package:lints/recommended.yaml'), - ), - ]), - ]).validate(); - }); - }); - - group('basic Flutter project template', () { - setUpAll(() async { - await (await projectCreator()) - .buildFlutterProjectTemplate(firebaseStyle: FirebaseStyle.none); - }); - - test('project directory is created', () async { - await d.dir('project_templates', [ - d.dir('flutter_project'), - ]).validate(); - }); - - test('Flutter Web directories are created', () async { - await d.dir('project_templates', [ - d.dir('flutter_project', [ - d.dir('lib'), - d.dir('web', [d.file('index.html', isEmpty)]), - ]) - ]).validate(); - }); - - test('pubspec is created', () async { - await d.dir('project_templates', [ - d.dir('flutter_project', [ - d.file( - 'pubspec.yaml', - allOf([ - contains('sdk: ^$languageVersion'), - matches('sdk: flutter'), - ]), - ), - ]), - ]).validate(); - }); - - test('pub get creates pubspec.lock', () async { - await d.dir('project_templates', [ - d.dir('flutter_project', [d.file('pubspec.lock', isNotEmpty)]), - ]).validate(); - }); - - test('flutter lints are enabled', () async { - await d.dir('project_templates', [ - d.dir('flutter_project', [ - d.file( - 'analysis_options.yaml', - matches('include: package:flutter_lints/flutter.yaml'), - ), - ]), - ]).validate(); - }); - - test('plugins are registered', () async { - await d.dir('project_templates', [ - d.dir('flutter_project/lib', [ - d.file( - 'generated_plugin_registrant.dart', - matches('FirebaseCoreWeb.registerWith'), - ), - ]), - ]).validate(); - }); - }); - - group('Firebase project template', () { - setUpAll(() async { - await (await projectCreator()).buildFlutterProjectTemplate( - firebaseStyle: FirebaseStyle.flutterFire); - }); - - test('project directory is created', () async { - await d.dir('project_templates', [ - d.dir('firebase_project'), - ]).validate(); - }); - - test('Flutter Web directories are created', () async { - await d.dir('project_templates', [ - d.dir('firebase_project', [ - d.dir('lib'), - d.dir('web', [d.file('index.html', isEmpty)]), - ]) - ]).validate(); - }); - - test('pubspec is created', () async { - await d.dir('project_templates', [ - d.dir('firebase_project', [ - d.file( - 'pubspec.yaml', - allOf([ - contains('sdk: ^$languageVersion'), - matches('sdk: flutter'), - ]), - ), - ]), - ]).validate(); - }); - - test('pub get creates pubspec.lock', () async { - await d.dir('project_templates', [ - d.dir('firebase_project', [d.file('pubspec.lock', isNotEmpty)]), - ]).validate(); - }); - - test('flutter lints are enabled', () async { - await d.dir('project_templates', [ - d.dir('firebase_project', [ - d.file( - 'analysis_options.yaml', - matches('include: package:flutter_lints/flutter.yaml'), - ), - ]), - ]).validate(); - }); - - test('generated_plugin_registrant.dart is created', () async { - await d.dir('project_templates', [ - d.dir('firebase_project', [ - d.dir('lib', [ + group('project templates', () { + group('dart', () { + setUpAll(() async { + await (await projectCreator()).buildDartProjectTemplate(); + }); + + test('project directory is created', () async { + await d.dir('project_templates', [ + d.dir('dart_project'), + ]).validate(); + }); + + test('pubspec is created', () async { + await d.dir('project_templates', [ + d.dir('dart_project', [ d.file( - 'generated_plugin_registrant.dart', - isNotEmpty, + 'pubspec.yaml', + allOf([ + contains('sdk: ^$languageVersion'), + ]), ), ]), - ]), - ]).validate(); - }); + ]).validate(); + }); + + test('pub get creates pubspec.lock', () async { + await d.dir('project_templates', [ + d.dir('dart_project', [d.file('pubspec.lock', isNotEmpty)]), + ]).validate(); + }); + + test('recommended lints are enabled', () async { + await d.dir('project_templates', [ + d.dir('dart_project', [ + d.file( + 'analysis_options.yaml', + matches('include: package:lints/recommended.yaml'), + ), + ]), + ]).validate(); + }); + }); + + group('flutter', () { + setUpAll(() async { + await (await projectCreator()) + .buildFlutterProjectTemplate(firebaseStyle: FirebaseStyle.none); + }); + + test('project directory is created', () async { + await d.dir('project_templates', [ + d.dir('flutter_project'), + ]).validate(); + }); + + test('Flutter Web directories are created', () async { + await d.dir('project_templates', [ + d.dir('flutter_project', [ + d.dir('lib'), + d.dir('web', [d.file('index.html', isEmpty)]), + ]) + ]).validate(); + }); + + test('pubspec is created', () async { + await d.dir('project_templates', [ + d.dir('flutter_project', [ + d.file( + 'pubspec.yaml', + allOf([ + contains('sdk: ^$languageVersion'), + matches('sdk: flutter'), + ]), + ), + ]), + ]).validate(); + }); + + test('pub get creates pubspec.lock', () async { + await d.dir('project_templates', [ + d.dir('flutter_project', [d.file('pubspec.lock', isNotEmpty)]), + ]).validate(); + }); + + test('flutter lints are enabled', () async { + await d.dir('project_templates', [ + d.dir('flutter_project', [ + d.file( + 'analysis_options.yaml', + matches('include: package:flutter_lints/flutter.yaml'), + ), + ]), + ]).validate(); + }); - test('plugins are registered', () async { - await d.dir('project_templates', [ - d.dir('firebase_project', [ - d.dir('lib', [ + test('plugins are registered', () async { + await d.dir('project_templates', [ + d.dir('flutter_project/lib', [ d.file( 'generated_plugin_registrant.dart', + matches('FirebaseCoreWeb.registerWith'), + ), + ]), + ]).validate(); + }); + }); + + group('firebase', () { + setUpAll(() async { + await (await projectCreator()).buildFlutterProjectTemplate( + firebaseStyle: FirebaseStyle.flutterFire); + }); + + test('project directory is created', () async { + await d.dir('project_templates', [ + d.dir('firebase_project'), + ]).validate(); + }); + + test('Flutter Web directories are created', () async { + await d.dir('project_templates', [ + d.dir('firebase_project', [ + d.dir('lib'), + d.dir('web', [d.file('index.html', isEmpty)]), + ]) + ]).validate(); + }); + + test('pubspec is created', () async { + await d.dir('project_templates', [ + d.dir('firebase_project', [ + d.file( + 'pubspec.yaml', allOf([ - matches('FirebaseFirestoreWeb.registerWith'), - matches('FirebaseAnalyticsWeb.registerWith'), - matches('FirebaseCoreWeb.registerWith'), - matches('FirebaseDatabaseWeb.registerWith'), - matches('FirebaseMessagingWeb.registerWith'), - matches('FirebaseStorageWeb.registerWith'), + contains('sdk: ^$languageVersion'), + matches('sdk: flutter'), ]), ), ]), - ]), - ]).validate(); + ]).validate(); + }); + + test('pub get creates pubspec.lock', () async { + await d.dir('project_templates', [ + d.dir('firebase_project', [d.file('pubspec.lock', isNotEmpty)]), + ]).validate(); + }); + + test('flutter lints are enabled', () async { + await d.dir('project_templates', [ + d.dir('firebase_project', [ + d.file( + 'analysis_options.yaml', + matches('include: package:flutter_lints/flutter.yaml'), + ), + ]), + ]).validate(); + }); + + test('generated_plugin_registrant.dart is created', () async { + await d.dir('project_templates', [ + d.dir('firebase_project', [ + d.dir('lib', [ + d.file( + 'generated_plugin_registrant.dart', + isNotEmpty, + ), + ]), + ]), + ]).validate(); + }); + + test('plugins are registered', () async { + await d.dir('project_templates', [ + d.dir('firebase_project', [ + d.dir('lib', [ + d.file( + 'generated_plugin_registrant.dart', + allOf([ + matches('FirebaseFirestoreWeb.registerWith'), + matches('FirebaseAnalyticsWeb.registerWith'), + matches('FirebaseCoreWeb.registerWith'), + matches('FirebaseDatabaseWeb.registerWith'), + matches('FirebaseMessagingWeb.registerWith'), + matches('FirebaseStorageWeb.registerWith'), + ]), + ), + ]), + ]), + ]).validate(); + }); }); }); } diff --git a/pkgs/dart_services/test/pub_test.dart b/pkgs/dart_services/test/pub_test.dart index 9501c3d06..9855ca741 100644 --- a/pkgs/dart_services/test/pub_test.dart +++ b/pkgs/dart_services/test/pub_test.dart @@ -8,49 +8,50 @@ import 'package:test/test.dart'; void main() => defineTests(); void defineTests() { - group('getAllImportsFor', () { - test('null', () { - expect(getAllImportsFor(null), isEmpty); - }); + group('pub', () { + group('getAllImportsFor', () { + test('null', () { + expect(getAllImportsFor(null), isEmpty); + }); - test('empty', () { - expect(getAllImportsFor(''), isEmpty); - expect(getAllImportsFor(' \n '), isEmpty); - }); + test('empty', () { + expect(getAllImportsFor(''), isEmpty); + expect(getAllImportsFor(' \n '), isEmpty); + }); - test('bad source', () { - final imports = getAllImportsFor('foo bar;\n baz\nimport mybad;\n'); - expect(imports, hasLength(1)); - expect(imports.single.uri.stringValue, equals('')); - }); + test('bad source', () { + final imports = getAllImportsFor('foo bar;\n baz\nimport mybad;\n'); + expect(imports, hasLength(1)); + expect(imports.single.uri.stringValue, equals('')); + }); - test('one', () { - const source = ''' + test('one', () { + const source = ''' library woot; import 'dart:math'; import 'package:foo/foo.dart'; void main() { } '''; - expect(getAllImportsFor(source).map((import) => import.uri.stringValue), - unorderedEquals(['dart:math', 'package:foo/foo.dart'])); - }); + expect(getAllImportsFor(source).map((import) => import.uri.stringValue), + unorderedEquals(['dart:math', 'package:foo/foo.dart'])); + }); - test('two', () { - const source = ''' + test('two', () { + const source = ''' library woot; import 'dart:math'; import 'package:foo/foo.dart'; import 'package:bar/bar.dart'; void main() { } '''; - expect( - getAllImportsFor(source).map((import) => import.uri.stringValue), - unorderedEquals( - ['dart:math', 'package:foo/foo.dart', 'package:bar/bar.dart'])); - }); + expect( + getAllImportsFor(source).map((import) => import.uri.stringValue), + unorderedEquals( + ['dart:math', 'package:foo/foo.dart', 'package:bar/bar.dart'])); + }); - test('three', () { - const source = ''' + test('three', () { + const source = ''' library woot; import 'dart:math'; import 'package:foo/foo.dart'; @@ -58,68 +59,69 @@ import 'package:bar/bar.dart';import 'package:baz/baz.dart'; import 'mybazfile.dart'; void main() { } '''; - expect( - getAllImportsFor(source).map((import) => import.uri.stringValue), - unorderedEquals([ - 'dart:math', - 'package:foo/foo.dart', - 'package:bar/bar.dart', - 'package:baz/baz.dart', - 'mybazfile.dart' - ])); + expect( + getAllImportsFor(source).map((import) => import.uri.stringValue), + unorderedEquals([ + 'dart:math', + 'package:foo/foo.dart', + 'package:bar/bar.dart', + 'package:baz/baz.dart', + 'mybazfile.dart' + ])); + }); }); - }); - group('filterSafePackagesFromImports', () { - test('empty', () { - const source = '''import 'package:'; + group('filterSafePackagesFromImports', () { + test('empty', () { + const source = '''import 'package:'; void main() { } '''; - expect(getAllImportsFor(source).filterSafePackages(), isEmpty); - }); + expect(filterSafePackages(getAllImportsFor(source)), isEmpty); + }); - test('simple', () { - const source = ''' + test('simple', () { + const source = ''' import 'package:foo/foo.dart'; import 'package:bar/bar.dart'; void main() { } '''; - expect(getAllImportsFor(source).filterSafePackages(), - unorderedEquals(['foo', 'bar'])); - }); + expect(filterSafePackages(getAllImportsFor(source)), + unorderedEquals(['foo', 'bar'])); + }); - test('defensive', () { - const source = ''' + test('defensive', () { + const source = ''' library woot; import 'dart:math'; import 'package:../foo/foo.dart'; void main() { } '''; - final imports = getAllImportsFor(source); - expect(imports, hasLength(2)); - expect(imports[0].uri.stringValue, equals('dart:math')); - expect(imports[1].uri.stringValue, equals('package:../foo/foo.dart')); - expect(imports.filterSafePackages(), isEmpty); - }); + final imports = getAllImportsFor(source); + expect(imports, hasLength(2)); + expect(imports[0].uri.stringValue, equals('dart:math')); + expect(imports[1].uri.stringValue, equals('package:../foo/foo.dart')); + expect(filterSafePackages(imports), isEmpty); + }); - test('negative dart import', () { - const source = ''' + test('negative dart import', () { + const source = ''' import 'dart:../bar.dart'; '''; - final imports = getAllImportsFor(source); - expect(imports, hasLength(1)); - expect(imports.single.uri.stringValue, equals('dart:../bar.dart')); - expect(imports.filterSafePackages(), isEmpty); - }); + final imports = getAllImportsFor(source); + expect(imports, hasLength(1)); + expect(imports.single.uri.stringValue, equals('dart:../bar.dart')); + expect(filterSafePackages(imports), isEmpty); + }); - test('negative path import', () { - const source = ''' + test('negative path import', () { + const source = ''' import '../foo.dart'; '''; - final imports = getAllImportsFor(source); - expect(imports, hasLength(1)); - expect(imports.single.uri.stringValue, equals('../foo.dart')); - expect(imports.filterSafePackages(), isEmpty); + final imports = getAllImportsFor(source); + expect(imports, hasLength(1)); + expect(imports.single.uri.stringValue, equals('../foo.dart')); + expect(filterSafePackages(imports), isEmpty); + }); }); }); } diff --git a/pkgs/dart_services/test/shelf_cors_test.dart b/pkgs/dart_services/test/shelf_cors_test.dart index 1be766437..59951bc98 100644 --- a/pkgs/dart_services/test/shelf_cors_test.dart +++ b/pkgs/dart_services/test/shelf_cors_test.dart @@ -16,7 +16,7 @@ void defineTests() { final request = shelf.Request('GET', Uri.parse('http://example.com/index.html')); - group('The corsHeaders middleware', () { + group('shelf_cors', () { test('adds default CORS headers to the response', () async { final middleware = shelf_cors.createCorsHeadersMiddleware(); final handler = middleware(handleAll); diff --git a/pkgs/dart_services/test/src/sample_code.dart b/pkgs/dart_services/test/src/sample_code.dart new file mode 100644 index 000000000..3aa5c462a --- /dev/null +++ b/pkgs/dart_services/test/src/sample_code.dart @@ -0,0 +1,725 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// 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. + +const sampleCode = ''' +void main() { + print("hello"); +} +'''; + +const sampleCodeWeb = """ +import 'dart:html'; + +void main() { + print("hello"); + querySelector('#foo')?.text = 'bar'; +} +"""; + +const sampleCodeFlutter = ''' +import 'package:flutter/material.dart'; + +void main() async { + runApp( + MaterialApp( + debugShowCheckedModeBanner: false, + home: Scaffold( + appBar: AppBar( + title: const Text('Hello, World!'), + ), + body: const Center( + child: Text( + 'Hello, World!', + ), + ), + ), + ), + ); +} +'''; + +// From https://gist.github.com/johnpryan/1a28bdd9203250d3226cc25d512579ec +const sampleCodeFlutterCounter = r''' +import 'package:flutter/material.dart'; + +void main() => runApp(const MyApp()); + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + debugShowCheckedModeBanner: false, + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + final String title; + const MyHomePage({ + super.key, + required this.title, + }); + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + int _counter = 0; + + void _incrementCounter() { + setState(() { + _counter++; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'You have pushed the button this many times:', + ), + Text( + '$_counter', + style: Theme.of(context).textTheme.headlineMedium, + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: const Icon(Icons.add), + ), + ); + } +} +'''; + +// From https://gist.github.com/RedBrogdon/e0a2e942e85fde2cd39b2741ff0c49e5 +const sampleCodeFlutterSunflower = r''' +import 'dart:math' as math; +import 'package:flutter/material.dart'; + +const Color primaryColor = Colors.orange; +const TargetPlatform platform = TargetPlatform.android; + +void main() { + runApp(Sunflower()); +} + +class SunflowerPainter extends CustomPainter { + static const seedRadius = 2.0; + static const scaleFactor = 4; + static const tau = math.pi * 2; + + static final phi = (math.sqrt(5) + 1) / 2; + + final int seeds; + + SunflowerPainter(this.seeds); + + @override + void paint(Canvas canvas, Size size) { + final center = size.width / 2; + + for (var i = 0; i < seeds; i++) { + final theta = i * tau / phi; + final r = math.sqrt(i) * scaleFactor; + final x = center + r * math.cos(theta); + final y = center - r * math.sin(theta); + final offset = Offset(x, y); + if (!size.contains(offset)) { + continue; + } + drawSeed(canvas, x, y); + } + } + + @override + bool shouldRepaint(SunflowerPainter oldDelegate) { + return oldDelegate.seeds != seeds; + } + + // Draw a small circle representing a seed centered at (x,y). + void drawSeed(Canvas canvas, double x, double y) { + final paint = Paint() + ..strokeWidth = 2 + ..style = PaintingStyle.fill + ..color = primaryColor; + canvas.drawCircle(Offset(x, y), seedRadius, paint); + } +} + +class Sunflower extends StatefulWidget { + @override + State createState() { + return _SunflowerState(); + } +} + +class _SunflowerState extends State { + double seeds = 100.0; + + int get seedCount => seeds.floor(); + + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + theme: ThemeData().copyWith( + platform: platform, + brightness: Brightness.dark, + sliderTheme: SliderThemeData.fromPrimaryColors( + primaryColor: primaryColor, + primaryColorLight: primaryColor, + primaryColorDark: primaryColor, + valueIndicatorTextStyle: const DefaultTextStyle.fallback().style, + ), + ), + home: Scaffold( + appBar: AppBar(title: const Text("Sunflower")), + drawer: Drawer( + child: ListView( + children: const [ + DrawerHeader( + child: Center( + child: Text( + "Sunflower 🌻", + style: TextStyle(fontSize: 32), + ), + ), + ), + ], + )), + body: Container( + constraints: const BoxConstraints.expand(), + decoration: + BoxDecoration(border: Border.all(color: Colors.transparent)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.transparent)), + child: SizedBox( + width: 400, + height: 400, + child: CustomPaint( + painter: SunflowerPainter(seedCount), + ), + ), + ), + Text("Showing $seedCount seeds"), + ConstrainedBox( + constraints: const BoxConstraints.tightFor(width: 300), + child: Slider.adaptive( + min: 20, + max: 2000, + value: seeds, + onChanged: (newValue) { + setState(() { + seeds = newValue; + }); + }, + ), + ), + ], + ), + ), + ), + ); + } +} +'''; + +// https://gist.github.com/johnpryan/5e28c5273c2c1a41d30bad9f9d11da56 +const sampleCodeFlutterDraggableCard = ''' +import 'package:flutter/material.dart'; +import 'package:flutter/physics.dart'; + +main() { + runApp( + MaterialApp( + debugShowCheckedModeBanner: false, + home: PhysicsCardDragDemo(), + ), + ); +} + +class PhysicsCardDragDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('A draggable card!'), + ), + body: const DraggableCard( + child: FlutterLogo( + size: 128, + ), + ), + ); + } +} + +class DraggableCard extends StatefulWidget { + final Widget child; + const DraggableCard({required this.child}); + + @override + State createState() => _DraggableCardState(); +} + +class _DraggableCardState extends State + with SingleTickerProviderStateMixin { + AnimationController? _controller; + Alignment _dragAlignment = Alignment.center; + Animation? _animation; + + void _runAnimation(Offset pixelsPerSecond, Size size) { + _animation = _controller!.drive( + AlignmentTween( + begin: _dragAlignment, + end: Alignment.center, + ), + ); + + final unitsPerSecondX = pixelsPerSecond.dx / size.width; + final unitsPerSecondY = pixelsPerSecond.dy / size.height; + final unitsPerSecond = Offset(unitsPerSecondX, unitsPerSecondY); + final unitVelocity = unitsPerSecond.distance; + + const spring = SpringDescription( + mass: 30, + stiffness: 1, + damping: 1, + ); + + final simulation = SpringSimulation(spring, 0, 1, -unitVelocity); + + _controller!.animateWith(simulation); + } + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this); + + _controller!.addListener(() { + setState(() { + _dragAlignment = _animation!.value; + }); + }); + } + + @override + void dispose() { + _controller!.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + return GestureDetector( + onPanDown: (details) { + _controller!.stop(); + }, + onPanUpdate: (details) { + setState(() { + _dragAlignment += Alignment( + details.delta.dx / (size.width / 2), + details.delta.dy / (size.height / 2), + ); + }); + }, + onPanEnd: (details) { + _runAnimation(details.velocity.pixelsPerSecond, size); + }, + child: Align( + alignment: _dragAlignment, + child: Card( + child: widget.child, + ), + ), + ); + } +} +'''; + +// From https://gist.github.com/johnpryan/289ecf8480ad005f01faeace70bd529a +const sampleCodeFlutterImplicitAnimations = ''' +import 'dart:math'; +import 'package:flutter/material.dart'; + +class DiscData { + static final _rng = Random(); + + final double size; + final Color color; + final Alignment alignment; + + DiscData() + : size = _rng.nextDouble() * 40 + 10, + color = Color.fromARGB( + _rng.nextInt(200), + _rng.nextInt(255), + _rng.nextInt(255), + _rng.nextInt(255), + ), + alignment = Alignment( + _rng.nextDouble() * 2 - 1, + _rng.nextDouble() * 2 - 1, + ); +} + +void main() async { + runApp( + MaterialApp( + debugShowCheckedModeBanner: false, + home: Scaffold( + body: Container( + color: const Color(0xFF15202D), + child: const SizedBox.expand( + child: VariousDiscs(50), + ), + ), + ), + ), + ); +} + +class VariousDiscs extends StatefulWidget { + final int numberOfDiscs; + + const VariousDiscs(this.numberOfDiscs); + + @override + State createState() => _VariousDiscsState(); +} + +class _VariousDiscsState extends State { + final _discs = []; + + @override + void initState() { + super.initState(); + _makeDiscs(); + } + + void _makeDiscs() { + _discs.clear(); + for (int i = 0; i < widget.numberOfDiscs; i++) { + _discs.add(DiscData()); + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => setState(() { + _makeDiscs(); + }), + child: Stack( + children: [ + const Center( + child: Text( + 'Click a disc!', + style: TextStyle(color: Colors.white, fontSize: 50), + ), + ), + for (final disc in _discs) + Positioned.fill( + child: AnimatedAlign( + duration: const Duration(milliseconds: 500), + curve: Curves.easeInOut, + alignment: disc.alignment, + child: AnimatedContainer( + duration: const Duration(milliseconds: 500), + decoration: BoxDecoration( + color: disc.color, + shape: BoxShape.circle, + ), + height: disc.size, + width: disc.size, + ), + ), + ), + ], + ), + ); + } +} +'''; + +const sampleCodeMultiFoo = """ +import 'bar.dart'; + +void main() { + print(bar()); +} +"""; + +const sampleCodeMultiBar = ''' +bar() { + return 4; +} +'''; + +const sampleCodeLibraryMultiFoo = """ +library foofoo; + +part 'bar.dart'; + +void main() { + print(bar()); +} +"""; + +const sampleCodePartMultiBar = ''' +part of foofoo; + +bar() { + return 4; +} +'''; + +const sampleCodeAsync = """ +import 'dart:html'; + +void main() async { + print("hello"); + querySelector('#foo')?.text = 'bar'; + var foo = await HttpRequest.getString('http://www.google.com'); + print(foo); +} +"""; + +const sampleCodeError = ''' +void main() { + print("hello") +} +'''; + +const sampleCodeErrors = ''' +void main() { + print1("hello"); + print2("hello"); + print3("hello"); +} +'''; + +const sampleDart2Error = ''' +class Foo { + final bool isAlwaysNull; + Foo(this.isAlwaysNull) {} +} + +void main(List argv) { + var x = new Foo(null); + var y = 1; + y = x; +} +'''; + +/// Code fragments for testing multi file compiling. +/// These fragments are taken from [sampleCodeFlutterImplicitAnimations] and +/// only separated and re-arranged to facilitate testing multi file tests. + +const sampleCode3PartFlutterImplicitAnimationsImports = r''' +import 'dart:math'; +import 'package:flutter/material.dart'; +'''; + +const sampleCode3PartFlutterImplicitAnimationsMain = r''' + +void main() async { + runApp( + MaterialApp( + debugShowCheckedModeBanner: false, + home: Scaffold( + body: Container( + color: const Color(0xFF15202D), + child: const SizedBox.expand( + child: VariousDiscs(50), + ), + ), + ), + ), + ); +} +'''; + +const sampleCode3PartFlutterImplicitAnimationsDiscData = r''' + +class DiscData { + static final _rng = Random(); + + final double size; + final Color color; + final Alignment alignment; + + DiscData() + : size = _rng.nextDouble() * 40 + 10, + color = Color.fromARGB( + _rng.nextInt(200), + _rng.nextInt(255), + _rng.nextInt(255), + _rng.nextInt(255), + ), + alignment = Alignment( + _rng.nextDouble() * 2 - 1, + _rng.nextDouble() * 2 - 1, + ); +} +'''; + +const sampleCode3PartFlutterImplicitAnimationsVarious = r''' + +class VariousDiscs extends StatefulWidget { + final int numberOfDiscs; + + const VariousDiscs(this.numberOfDiscs); + + @override + State createState() => _VariousDiscsState(); +} + +class _VariousDiscsState extends State { + final _discs = []; + + @override + void initState() { + super.initState(); + _makeDiscs(); + } + + void _makeDiscs() { + _discs.clear(); + for (int i = 0; i < widget.numberOfDiscs; i++) { + _discs.add(DiscData()); + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => setState(() { + _makeDiscs(); + }), + child: Stack( + children: [ + const Center( + child: Text( + 'Click a disc!', + style: TextStyle(color: Colors.white, fontSize: 50), + ), + ), + for (final disc in _discs) + Positioned.fill( + child: AnimatedAlign( + duration: const Duration(milliseconds: 500), + curve: Curves.easeInOut, + alignment: disc.alignment, + child: AnimatedContainer( + duration: const Duration(milliseconds: 500), + decoration: BoxDecoration( + color: disc.color, + shape: BoxShape.circle, + ), + height: disc.size, + width: disc.size, + ), + ), + ), + ], + ), + ); + } +} +'''; + +/// Create 2 files for multi file testing using imports. +const sampleCode2PartImportMain = ''' +$sampleCode3PartFlutterImplicitAnimationsImports +import 'various.dart'; +$sampleCode3PartFlutterImplicitAnimationsMain +'''; + +const sampleCode2PartImportVarious = ''' +$sampleCode3PartFlutterImplicitAnimationsImports +$sampleCode3PartFlutterImplicitAnimationsDiscData +$sampleCode3PartFlutterImplicitAnimationsVarious +'''; + +/// Create 3 separate files for multi file testing using imports. +/// Here main.dart will be importing 'various.dart' and 'discdata.dart', +/// and 'various.dart' importing 'discdata.dart'. +const sampleCode3PartImportMain = ''' +$sampleCode3PartFlutterImplicitAnimationsImports +import 'various.dart'; +import 'discdata.dart'; +$sampleCode3PartFlutterImplicitAnimationsMain +'''; + +const sampleCode3PartImportDiscData = ''' +$sampleCode3PartFlutterImplicitAnimationsImports +$sampleCode3PartFlutterImplicitAnimationsDiscData +'''; + +const sampleCode3PartImportVarious = ''' +$sampleCode3PartFlutterImplicitAnimationsImports +import 'discdata.dart'; +$sampleCode3PartFlutterImplicitAnimationsVarious +'''; + +/// Create 2 file test using "part 'various.dart'" to bring in second file. +const sampleCode2PartLibraryMain = ''' +library testanim; +$sampleCode3PartFlutterImplicitAnimationsImports +part 'various.dart'; +$sampleCode3PartFlutterImplicitAnimationsMain +'''; + +const sampleCode2PartVariousAndDiscDataPartOfTestAnim = ''' +part of testanim; +$sampleCode3PartFlutterImplicitAnimationsDiscData +$sampleCode3PartFlutterImplicitAnimationsVarious +'''; + +/// Create 3 file test using "part 'various.dart'" and "part 'discdata.dart'" +/// to bring in second and third files. +const sampleCode3PartLibraryMain = ''' +library testanim; +$sampleCode3PartFlutterImplicitAnimationsImports +part 'discdata.dart'; +part 'various.dart'; +$sampleCode3PartFlutterImplicitAnimationsMain +'''; + +const sampleCode3PartDiscDataPartOfTestAnim = ''' +part of testanim; +$sampleCode3PartFlutterImplicitAnimationsDiscData +'''; + +const sampleCode3PartVariousPartOfTestAnim = ''' +part of testanim; +$sampleCode3PartFlutterImplicitAnimationsVarious +'''; diff --git a/pkgs/dart_services/test/src/utils.dart b/pkgs/dart_services/test/src/utils.dart index d9f12f147..f1e1e38ca 100644 --- a/pkgs/dart_services/test/src/utils.dart +++ b/pkgs/dart_services/test/src/utils.dart @@ -4,10 +4,7 @@ import 'dart:collection'; -import 'package:dart_services/src/server_cache.dart'; - -export 'package:angel3_mock_request/angel3_mock_request.dart' - show MockHttpRequest, MockHttpResponse; +import 'package:dart_services/src/caching.dart'; class MockCache implements ServerCache { final _cache = HashMap(); diff --git a/pkgs/dart_services/test/utils_test.dart b/pkgs/dart_services/test/utils_test.dart index c0a160a94..68d4e6644 100644 --- a/pkgs/dart_services/test/utils_test.dart +++ b/pkgs/dart_services/test/utils_test.dart @@ -5,57 +5,61 @@ import 'package:dart_services/src/utils.dart'; import 'package:test/test.dart'; -void main() { +void main() => defineTests(); + +void defineTests() { void expectNormalizeFilePaths(String input, String output) { expect(normalizeFilePaths(input), equals(output)); } - test('normalizeFilePaths strips a temporary directory path', () { - expectNormalizeFilePaths( - 'List is defined in /var/folders/4p/y54w9nqj0_n6ryqwn7lxqz6800m6cw/T/DartAnalysisWrapperintLAw/main.dart', - 'List is defined in main.dart', - ); - }); + group('expectNormalizeFilePaths', () { + test('strips a temporary directory path', () { + expectNormalizeFilePaths( + 'List is defined in /var/folders/4p/y54w9nqj0_n6ryqwn7lxqz6800m6cw/T/DartAnalysisWrapperintLAw/main.dart', + 'List is defined in main.dart', + ); + }); - test('normalizeFilePaths replaces a SDK path with "dart:core"', () { - expectNormalizeFilePaths( - 'List is defined in /path/dart/dart/sdk/lib/core/list.dart', - 'List is defined in dart:core/list.dart', - ); - }); + test('replaces a SDK path with "dart:core"', () { + expectNormalizeFilePaths( + 'List is defined in /path/dart/dart/sdk/lib/core/list.dart', + 'List is defined in dart:core/list.dart', + ); + }); - test('normalizeFilePaths replaces a specific SDK path with "dart:core"', () { - expectNormalizeFilePaths( - "The argument type 'List (where List is defined in /Users/username/sdk/dart/2.10.5/lib/core/list.dart)' can't be assigned to the parameter type 'List (where List is defined in /var/folders/4p/tmp/T/DartAnalysisWrapperintLAw/main.dart)'.", - "The argument type 'List (where List is defined in dart:core/list.dart)' can't be assigned to the parameter type 'List (where List is defined in main.dart)'.", - ); - }); + test('replaces a specific SDK path with "dart:core"', () { + expectNormalizeFilePaths( + "The argument type 'List (where List is defined in /Users/username/sdk/dart/2.10.5/lib/core/list.dart)' can't be assigned to the parameter type 'List (where List is defined in /var/folders/4p/tmp/T/DartAnalysisWrapperintLAw/main.dart)'.", + "The argument type 'List (where List is defined in dart:core/list.dart)' can't be assigned to the parameter type 'List (where List is defined in main.dart)'.", + ); + }); - test('normalizeFilePaths keeps a "package:" path intact', () { - expectNormalizeFilePaths( - "Unused import: 'package:flutter/material.dart'.", - "Unused import: 'package:flutter/material.dart'.", - ); - }); + test('keeps a "package:" path intact', () { + expectNormalizeFilePaths( + "Unused import: 'package:flutter/material.dart'.", + "Unused import: 'package:flutter/material.dart'.", + ); + }); - test('normalizeFilePaths keeps a "dart:core" path intact', () { - expectNormalizeFilePaths( - 'dart:core/foo.dart', - 'dart:core/foo.dart', - ); - }); + test('keeps a "dart:core" path intact', () { + expectNormalizeFilePaths( + 'dart:core/foo.dart', + 'dart:core/foo.dart', + ); + }); - test('normalizeFilePaths keeps a web URL intact', () { - expectNormalizeFilePaths( - 'See http://dart.dev/go/non-promo-property', - 'See http://dart.dev/go/non-promo-property', - ); - }); + test('keeps a web URL intact', () { + expectNormalizeFilePaths( + 'See http://dart.dev/go/non-promo-property', + 'See http://dart.dev/go/non-promo-property', + ); + }); - test('normalizeFilePaths strips a Flutter SDK path', () { - expectNormalizeFilePaths( - "The argument type 'StatelessWidget (where StatelessWidget is defined in /Users/username/path/to/dart-services/project_templates/flutter_project/main.dart)' can't be assigned to the parameter type 'StatelessWidget (where StatelessWidget is defined in /Users/username/path/to/dart-services/flutter-sdk/packages/flutter/lib/src/widgets/framework.dart)'.", - "The argument type 'StatelessWidget (where StatelessWidget is defined in main.dart)' can't be assigned to the parameter type 'StatelessWidget (where StatelessWidget is defined in package:flutter/framework.dart)'.", - ); + test('strips a Flutter SDK path', () { + expectNormalizeFilePaths( + "The argument type 'StatelessWidget (where StatelessWidget is defined in /Users/username/path/to/dart-services/project_templates/flutter_project/main.dart)' can't be assigned to the parameter type 'StatelessWidget (where StatelessWidget is defined in /Users/username/path/to/dart-services/flutter-sdk/packages/flutter/lib/src/widgets/framework.dart)'.", + "The argument type 'StatelessWidget (where StatelessWidget is defined in main.dart)' can't be assigned to the parameter type 'StatelessWidget (where StatelessWidget is defined in package:flutter/framework.dart)'.", + ); + }); }); } diff --git a/pkgs/dart_services/tool/dependencies/pub_dependencies_main.json b/pkgs/dart_services/tool/dependencies/pub_dependencies_main.json index 5423374d4..2579a76af 100644 --- a/pkgs/dart_services/tool/dependencies/pub_dependencies_main.json +++ b/pkgs/dart_services/tool/dependencies/pub_dependencies_main.json @@ -103,7 +103,7 @@ "path_provider_windows": "2.2.1", "petitparser": "6.0.1", "platform": "3.1.3", - "plugin_platform_interface": "2.1.6", + "plugin_platform_interface": "2.1.7", "pointycastle": "3.7.3", "polylabel": "1.0.1", "pool": "1.5.1", diff --git a/pkgs/dart_services/tool/grind.dart b/pkgs/dart_services/tool/grind.dart index 48b353220..1a4212814 100644 --- a/pkgs/dart_services/tool/grind.dart +++ b/pkgs/dart_services/tool/grind.dart @@ -8,8 +8,8 @@ import 'dart:async'; import 'dart:convert' show JsonEncoder; import 'dart:io'; -import 'package:dart_services/src/project.dart'; import 'package:dart_services/src/project_creator.dart'; +import 'package:dart_services/src/project_templates.dart'; import 'package:dart_services/src/pub.dart'; import 'package:dart_services/src/sdk.dart'; import 'package:dart_services/src/utils.dart'; @@ -120,8 +120,11 @@ void buildStorageArtifacts() async { } } -Future _buildStorageArtifacts(Directory dir, Sdk sdk, - {required String channel}) async { +Future _buildStorageArtifacts( + Directory dir, + Sdk sdk, { + required String channel, +}) async { final dependenciesFile = _pubDependenciesFile(channel: channel); final pubspec = createPubspec( includeFlutterWeb: true, @@ -150,7 +153,7 @@ Future _buildStorageArtifacts(Directory dir, Sdk sdk, '''); - await runFlutterPackagesGet(sdk.flutterToolPath, dir.path, log: log); + await runFlutterPubGet(sdk, dir.path, log: log); // Working around Flutter 3.3's deprecation of generated_plugin_registrant.dart // Context: https://github.com/flutter/flutter/pull/106921 @@ -251,30 +254,8 @@ void deploy() { log('Deploy via Google Cloud Console'); } -@Task('Generate Protobuf classes') -void generateProtos() async { - try { - await _run( - 'protoc', - arguments: ['--dart_out=lib/src', 'protos/dart_services.proto'], - ); - } catch (e) { - print('Error running "protoc"; make sure the Protocol Buffer compiler is ' - 'installed (see README.md)'); - } - - // reformat generated classes so CI checks don't fail - await _run( - 'dart', - arguments: ['format', '--fix', 'lib/src/protos'], - ); - - // And reformat again, for $REASONS - await _run( - 'dart', - arguments: ['format', '--fix', 'lib/src/protos'], - ); - +@Task('Copy shared source from dartpad_shared') +void copySharedSource() async { // TODO: We'd like to remove this copy operation; that will require work in // the cloud build configuration. copy(getDir('../dartpad_shared/lib'), getDir('lib/src/shared')); @@ -301,8 +282,7 @@ Future _run( @Depends(buildProjectTemplates) void updatePubDependencies() async { final sdk = Sdk(); - await _updateDependenciesFile( - flutterToolPath: sdk.flutterToolPath, channel: sdk.channel, sdk: sdk); + await _updateDependenciesFile(channel: sdk.channel, sdk: sdk); } /// Updates the "dependencies file". @@ -313,7 +293,6 @@ void updatePubDependencies() async { /// /// See [_pubDependenciesFile] for the location of the dependencies files. Future _updateDependenciesFile({ - required String flutterToolPath, required String channel, required Sdk sdk, }) async { @@ -340,7 +319,7 @@ Future _updateDependenciesFile({ dependencies: dependencies, ); joinFile(tempDir, ['pubspec.yaml']).writeAsStringSync(pubspec); - await runFlutterPackagesGet(flutterToolPath, tempDir.path, log: log); + await runFlutterPubGet(sdk, tempDir.path, log: log); final packageVersions = packageVersionsFromPubspecLock(tempDir.path); _pubDependenciesFile(channel: channel).writeAsStringSync( diff --git a/pkgs/dartpad_shared/lib/model.dart b/pkgs/dartpad_shared/lib/model.dart index 50b093274..c27d74870 100644 --- a/pkgs/dartpad_shared/lib/model.dart +++ b/pkgs/dartpad_shared/lib/model.dart @@ -43,6 +43,7 @@ class AnalysisIssue { final String kind; final String message; final Location location; + final String? code; final String? correction; final String? url; final List? contextMessages; @@ -53,6 +54,7 @@ class AnalysisIssue { required this.kind, required this.message, required this.location, + this.code, this.correction, this.url, this.contextMessages, @@ -64,6 +66,15 @@ class AnalysisIssue { Map toJson() => _$AnalysisIssueToJson(this); + int get severity { + return switch (kind) { + 'error' => 3, + 'warning' => 2, + 'info' => 1, + _ => 0, + }; + } + @override String toString() => '[$kind] $message'; } @@ -163,18 +174,6 @@ class FormatResponse { String toString() => 'FormatResponse[source=$source,offset=$offset]'; } -@JsonSerializable() -class FlutterBuildResponse { - final Map artifacts; - - FlutterBuildResponse({required this.artifacts}); - - factory FlutterBuildResponse.fromJson(Map json) => - _$FlutterBuildResponseFromJson(json); - - Map toJson() => _$FlutterBuildResponseToJson(this); -} - @JsonSerializable() class FixesResponse { static final FixesResponse empty = FixesResponse( diff --git a/pkgs/dartpad_shared/lib/model.g.dart b/pkgs/dartpad_shared/lib/model.g.dart index f670137e0..5e9577936 100644 --- a/pkgs/dartpad_shared/lib/model.g.dart +++ b/pkgs/dartpad_shared/lib/model.g.dart @@ -39,6 +39,7 @@ AnalysisIssue _$AnalysisIssueFromJson(Map json) => kind: json['kind'] as String, message: json['message'] as String, location: Location.fromJson(json['location'] as Map), + code: json['code'] as String?, correction: json['correction'] as String?, url: json['url'] as String?, contextMessages: (json['contextMessages'] as List?) @@ -52,6 +53,7 @@ Map _$AnalysisIssueToJson(AnalysisIssue instance) => 'kind': instance.kind, 'message': instance.message, 'location': instance.location, + 'code': instance.code, 'correction': instance.correction, 'url': instance.url, 'contextMessages': instance.contextMessages, @@ -128,18 +130,6 @@ Map _$FormatResponseToJson(FormatResponse instance) => 'offset': instance.offset, }; -FlutterBuildResponse _$FlutterBuildResponseFromJson( - Map json) => - FlutterBuildResponse( - artifacts: Map.from(json['artifacts'] as Map), - ); - -Map _$FlutterBuildResponseToJson( - FlutterBuildResponse instance) => - { - 'artifacts': instance.artifacts, - }; - FixesResponse _$FixesResponseFromJson(Map json) => FixesResponse( fixes: (json['fixes'] as List) diff --git a/pkgs/dartpad_shared/lib/services.dart b/pkgs/dartpad_shared/lib/services.dart index 29dd904cf..ee49d2941 100644 --- a/pkgs/dartpad_shared/lib/services.dart +++ b/pkgs/dartpad_shared/lib/services.dart @@ -40,11 +40,6 @@ class ServicesClient { Future compileDDC(CompileRequest request) => _requestPost('compileDDC', request.toJson(), CompileDDCResponse.fromJson); - /// Note that this call is experimental and can change at any time. - Future flutterBuild(SourceRequest request) => - _requestPost( - '_flutterBuild', request.toJson(), FlutterBuildResponse.fromJson); - void dispose() => client.close(); Future _requestGet( diff --git a/pkgs/samples/pubspec.yaml b/pkgs/samples/pubspec.yaml index 58decd791..90e3ae7b7 100644 --- a/pkgs/samples/pubspec.yaml +++ b/pkgs/samples/pubspec.yaml @@ -11,8 +11,6 @@ dependencies: dev_dependencies: args: ^2.4.0 -# flutter_test: -# sdk: flutter flutter_lints: ^3.0.0 path: ^1.8.0 diff --git a/pkgs/sketch_pad/lib/model.dart b/pkgs/sketch_pad/lib/model.dart index 2338efaed..6721a736e 100644 --- a/pkgs/sketch_pad/lib/model.dart +++ b/pkgs/sketch_pad/lib/model.dart @@ -345,17 +345,6 @@ class AppServices { } } -extension AnalysisIssueExtension on AnalysisIssue { - int get severity { - return switch (kind) { - 'error' => 3, - 'warning' => 2, - 'info' => 1, - _ => 0, - }; - } -} - enum Channel { stable('Stable', 'https://stable.api.dartpad.dev/'), beta('Beta', 'https://beta.api.dartpad.dev/'), @@ -367,7 +356,7 @@ enum Channel { const Channel(this.displayName, this.url); - static const defaultChannel = Channel.stable; + static const defaultChannel = Channel.localhost; static List get valuesWithoutLocalhost { return values.whereNot((channel) => channel == localhost).toList(); diff --git a/pkgs/sketch_pad/pubspec.yaml b/pkgs/sketch_pad/pubspec.yaml index 99e22eb9f..588a06d3b 100644 --- a/pkgs/sketch_pad/pubspec.yaml +++ b/pkgs/sketch_pad/pubspec.yaml @@ -16,7 +16,6 @@ dependencies: http: any json_annotation: ^4.8.1 pointer_interceptor: ^0.9.0 - protobuf: any provider: ^6.0.0 split_view: ^3.2.0 url_launcher: any From 93c10d7df7dca9f70c9cdb68841e74aaa2cde324 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Sat, 18 Nov 2023 15:27:41 -0800 Subject: [PATCH 2/5] address todos; update docs --- CONTRIBUTING.md | 33 +-- pkgs/dart_services/LICENSE | 2 +- pkgs/dart_services/README.md | 59 ++--- pkgs/dart_services/dart_test.yaml | 6 + pkgs/dart_services/lib/src/analysis.dart | 247 ++++++------------ pkgs/dart_services/lib/src/common_server.dart | 24 +- .../lib/src/project_creator.dart | 10 +- .../lib/src/project_templates.dart | 137 +++++----- pkgs/dart_services/lib/src/pub.dart | 7 +- pkgs/dart_services/lib/src/sdk.dart | 10 +- pkgs/dart_services/pubspec.yaml | 4 +- pkgs/dart_services/test/analysis_test.dart | 16 +- pkgs/dart_services/test/caching_test.dart | 2 - pkgs/dart_services/tool/grind.dart | 4 +- 14 files changed, 233 insertions(+), 328 deletions(-) create mode 100644 pkgs/dart_services/dart_test.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 03dfee282..fbb9104a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing to DartPad + Want to contribute? Great! First, read this page (including the small print at the end). ## Before you contribute @@ -40,36 +41,10 @@ Contributions made by corporations are covered by a different agreement than the ## How to run DartPad locally -* To run the DartPad against the regular serving backend: +To run the server, see https://github.com/dart-lang/dart-pad/blob/main/pkgs/dart_services/README.md. -Run these commands: +To run the front-end, from the `pkg/dart-pad` directory, run: -```bash -# Get all Dart dependencies -dart pub get -# Install the Dart grinder tool -dart pub global activate grinder -# Serve -grind serve ``` -This serves the DartPad frontend locally on port 8000. - -* To run DartPad against a local version of the dart-services backend: -```bash -cd .. -git clone git@github.com:dart-lang/dart-services.git -cd dart-services -dart pub get -# Change the SDK version dart-services serves to the one you currently have installed -grind update-docker-version -# Begin serving the backend locally on port 8080. -FLUTTER_CHANNEL="stable" grind serve & - -cd ../dart-pad -# Begin serving the front-end locally on port 8000, with the given backend on the default port 8080 this is defined in tools/grind.dart -grind serve-local-backend +dart tool/grind.dart serve ``` - -You can adjust the DARTPAD_BACKEND variable to match different versions of the dart-pad backend -serving on AppEngine for test purposes as well, e.g.: -`DARTPAD_BACKEND=https://20180822t110058-dot-dart-services.appspot.com/` diff --git a/pkgs/dart_services/LICENSE b/pkgs/dart_services/LICENSE index 000cd7bec..162572a44 100644 --- a/pkgs/dart_services/LICENSE +++ b/pkgs/dart_services/LICENSE @@ -1,4 +1,4 @@ -Copyright 2014, the Dart project authors. +Copyright 2014, the Dart project authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/pkgs/dart_services/README.md b/pkgs/dart_services/README.md index f9dd465f4..830b470be 100644 --- a/pkgs/dart_services/README.md +++ b/pkgs/dart_services/README.md @@ -6,52 +6,48 @@ A server backend to support DartPad. ## What is it? What does it do? -This project is a small, stateless Dart server, which powers the front-end of DartPad. -It provides many of DartPad's features, including static analysis (errors and warnings), -compilation to JavaScript, code completion, dartdoc information, code formatting, and -quick fixes for issues. +This project is a small, stateless Dart server, which powers the front-end of +DartPad. It provides many of DartPad's features, including static analysis +(errors and warnings), compilation to JavaScript, code completion, dartdoc +information, code formatting, and quick fixes for issues. ## Getting set up -This project is built with [grinder](https://pub.dev/packages/grinder). To install, please run: +### Initialize Flutter -```bash -$ dart pub global activate grinder -``` +The Flutter SDK needs to be downloaded and setup; see +https://docs.flutter.dev/get-started/install. -## Initialize Flutter +### Running -The Flutter SDK needs to be downloaded and setup. +To run the server, run: ```bash -$ dart pub get -$ dart run tool/update_sdk.dart stable +$ dart bin/server.dart ``` -## Build the subsidiary files +The server will run from port 8080 and export several JSON APIs, like +`/api/v3/analyze` and `/api/v3/compile`. -The Dart Services server depends on generated files. Run the following to generate all the required binaries. +### Testing -```bash -$ dart tool/grind.dart deploy -``` +To run tests: -## Running +`dart test` -To run the server, run: +### Re-renerating source -```bash -$ dart tool/grind.dart serve -``` +To rebuild the shelf router, run: -The server will run from port 8080 and export several JSON APIs, like -`/api/v3/compile` and `/api/v3/analyze`. +``` +dart run build_runner build --delete-conflicting-outputs +``` -## Testing +And to update the shared code from dartpad_shared, run: -To run tests: - -`dart test` +``` +dart tool/grind.dart copy-shared-source +``` ## Redis @@ -63,12 +59,11 @@ To configure the server to use the local redis cache, run `dart bin/server.dart` ## Issues and bugs -Please file reports on the -[GitHub Issue Tracker for DartPad](https://github.com/dart-lang/dart-pad/issues). +Please report issues at https://github.com/dart-lang/dart-pad/issues. ## License and Contributing Contributions welcome! Please read this short -[guide](https://github.com/dart-lang/dart-services/wiki/Contributing) first. +[guide](https://github.com/dart-lang/dart-pad/blob/main/CONTRIBUTING.md) first. You can view our license -[here](https://github.com/dart-lang/dart-services/blob/master/LICENSE). +[here](https://github.com/dart-lang/dart-pad/blob/main/LICENSE). diff --git a/pkgs/dart_services/dart_test.yaml b/pkgs/dart_services/dart_test.yaml new file mode 100644 index 000000000..7cbb358b7 --- /dev/null +++ b/pkgs/dart_services/dart_test.yaml @@ -0,0 +1,6 @@ +# Configure test execution; documentation available at: +# https://github.com/dart-lang/test/blob/master/pkgs/test/doc/configuration.md. + +# Some of the project_creator_test.dart tests don't like to run in parallel with +# other tests. +concurrency: 1 diff --git a/pkgs/dart_services/lib/src/analysis.dart b/pkgs/dart_services/lib/src/analysis.dart index 4c6f4316e..38891bc47 100644 --- a/pkgs/dart_services/lib/src/analysis.dart +++ b/pkgs/dart_services/lib/src/analysis.dart @@ -15,26 +15,24 @@ import 'common_server.dart'; import 'project_templates.dart' as project; import 'project_templates.dart'; import 'pub.dart'; +import 'sdk.dart'; import 'shared/model.dart' as api; import 'utils.dart' as utils; final Logger _logger = Logger('analysis_server'); -// todo: remove this class? -class AnalyzerWrapper { - final String dartSdkPath; +class Analyzer { + final Sdk sdk; - late DartAnalysisServerWrapper _dartAnalysisServer; + late AnalysisServerWrapper analysisServer; - AnalyzerWrapper(this.dartSdkPath); + Analyzer(this.sdk); Future init() async { - _logger.fine('Beginning AnalysisServersWrapper init().'); - _dartAnalysisServer = DartAnalysisServerWrapper(sdkPath: dartSdkPath); - await _dartAnalysisServer.init(); - _logger.info('Analysis server initialized.'); + analysisServer = AnalysisServerWrapper(sdkPath: sdk.dartSdkPath); + await analysisServer.init(); - unawaited(_dartAnalysisServer.onExit.then((int code) { + unawaited(analysisServer.onExit.then((int code) { _logger.severe('analysis server exited, code: $code'); if (code != 0) { exit(code); @@ -42,69 +40,38 @@ class AnalyzerWrapper { })); } - // todo: inline this - Future analyze(String source) { - return _perfLogAndRestart( - source, - kMainDart, - 0, - (List imports, int? offset) => - _dartAnalysisServer.analyze(source, imports: imports), - 'analysis', - 'Error during analyze', - ); - } + Future analyze(String source) async { + final imports = getAllImportsFor(source); - // todo: inline this - Future completeV3(String source, int offset) { - // todo: sanitize imports - return _dartAnalysisServer.completeV3(source, offset); + // TODO(srawlins): Do the work so that each unsupported input is its own + // error with a proper SourceSpan. + await _checkPackageReferences(imports); + + return analysisServer.analyze(source, imports: imports); } - // todo: inline this - Future fixesV3(String source, int offset) { - // todo: sanitize imports - return _dartAnalysisServer.fixesV3(source, offset); + Future completeV3(String source, int offset) async { + await _checkPackageReferences(getAllImportsFor(source)); + + return analysisServer.completeV3(source, offset); } - // todo: inline this - Future format(String source, int? offset) { - return _perfLogAndRestart( - source, - kMainDart, - offset, - (List imports, int? offset) => - _dartAnalysisServer.format(source, offset), - 'format', - 'Error during format at $offset', - ); + Future fixesV3(String source, int offset) async { + await _checkPackageReferences(getAllImportsFor(source)); + + return analysisServer.fixesV3(source, offset); } - // todo: inline this - Future dartdocV3(String source, int offset) { - // todo: sanitize imports - return _dartAnalysisServer.dartdocV3(source, offset); + Future format(String source, int? offset) async { + await _checkPackageReferences(getAllImportsFor(source)); + + return analysisServer.format(source, offset); } - Future _perfLogAndRestart( - String source, - String activeSourceName, - int? offset, - Future Function(List, int?) body, - String action, - String errorDescription, - ) async { - final imports = getAllImportsFor(source); - await _checkPackageReferences(imports); - try { - final watch = Stopwatch()..start(); - final response = await body(imports, offset); - _logger.fine('PERF: Computed $action in ${watch.elapsedMilliseconds}ms.'); - return response; - } catch (e, st) { - _logger.severe(errorDescription, e, st); - rethrow; - } + Future dartdocV3(String source, int offset) async { + await _checkPackageReferences(getAllImportsFor(source)); + + return analysisServer.dartdocV3(source, offset); } /// Check that the set of packages referenced is valid. @@ -115,8 +82,6 @@ class AnalyzerWrapper { ); if (unsupportedImports.isNotEmpty) { - // TODO(srawlins): Do the work so that each unsupported input is its own - // error, with a proper SourceSpan. final unsupportedUris = unsupportedImports.map((import) => import.uri.stringValue); throw BadRequest('Unsupported import(s): $unsupportedUris'); @@ -124,18 +89,18 @@ class AnalyzerWrapper { } Future shutdown() { - return _dartAnalysisServer.shutdown(); + return analysisServer.shutdown(); } } -class DartAnalysisServerWrapper { +class AnalysisServerWrapper { final String sdkPath; final String projectPath; /// Instance to handle communication with the server. late AnalysisServer analysisServer; - DartAnalysisServerWrapper({ + AnalysisServerWrapper({ required this.sdkPath, String? projectPath, }) : @@ -198,13 +163,21 @@ class DartAnalysisServerWrapper { }).where((CompletionSuggestion suggestion) { if (suggestion.kind != 'IMPORT') return true; - // todo: filter package suggestions to allowlisted packages - // We do not want to enable arbitrary discovery of file system resources. // In order to avoid returning local file paths, we only allow returning // import kinds that are dart: or package: imports. - return suggestion.completion.startsWith('dart:') || - suggestion.completion.startsWith('package:'); + if (suggestion.completion.startsWith('dart:')) { + return true; + } + + // Filter package suggestions to allowlisted packages. + if (suggestion.completion.startsWith('package:')) { + var packageName = suggestion.completion.substring('package:'.length); + packageName = packageName.split('/').first; + return isSupportedPackage(packageName); + } + + return false; }).toList(); suggestions.sort((CompletionSuggestion x, CompletionSuggestion y) { @@ -237,34 +210,29 @@ class DartAnalysisServerWrapper { Future fixesV3(String src, int offset) async { final mainFile = _getPathFromName(kMainDart); - final overlay = {mainFile: src}; - await _loadSources(overlay); + await _loadSources({mainFile: src}); - try { - final fixes = await analysisServer.edit.getFixes(mainFile, offset); - final assists = await analysisServer.edit.getAssists(mainFile, offset, 1); + final fixes = await analysisServer.edit.getFixes(mainFile, offset); + final assists = await analysisServer.edit.getAssists(mainFile, offset, 1); - final fixChanges = fixes.fixes.expand((fixes) => fixes.fixes).toList(); - final assistsChanges = assists.assists; + final fixChanges = fixes.fixes.expand((fixes) => fixes.fixes).toList(); + final assistsChanges = assists.assists; - // Filter any source changes that want to act on files other than main.dart. - fixChanges.removeWhere( - (change) => change.edits.any((edit) => edit.file != mainFile)); - assistsChanges.removeWhere( - (change) => change.edits.any((edit) => edit.file != mainFile)); + // Filter any source changes that want to act on files other than main.dart. + fixChanges.removeWhere( + (change) => change.edits.any((edit) => edit.file != mainFile)); + assistsChanges.removeWhere( + (change) => change.edits.any((edit) => edit.file != mainFile)); - return api.FixesResponse( - fixes: fixChanges.map((change) { - return change.toApiSourceChange(); - }).toList(), - assists: assistsChanges.map((change) { - return change.toApiSourceChange(); - }).toList(), - ); - } finally { - await _unloadSources(); - } + return api.FixesResponse( + fixes: fixChanges.map((change) { + return change.toApiSourceChange(); + }).toList(), + assists: assistsChanges.map((change) { + return change.toApiSourceChange(); + }).toList(), + ); } /// Format the source [src] of the single passed in file. The [offset] is the @@ -293,13 +261,11 @@ class DartAnalysisServerWrapper { } Future dartdocV3(String src, int offset) async { - final sources = _getOverlayMapWithPaths({kMainDart: src}); final sourcepath = _getPathFromName(kMainDart); - await _loadSources(sources); + await _loadSources(_getOverlayMapWithPaths({kMainDart: src})); final result = await analysisServer.analysis.getHover(sourcepath, offset); - await _unloadSources(); if (result.hovers.isEmpty) { return api.DocumentResponse(); @@ -331,7 +297,6 @@ class DartAnalysisServerWrapper { errors .addAll((await analysisServer.analysis.getErrors(sourcepath)).errors); } - await _unloadSources(); final issues = errors.map((error) { final issue = api.AnalysisIssue( @@ -385,43 +350,24 @@ class DartAnalysisServerWrapper { } /// Cleanly shutdown the Analysis Server. - Future shutdown() { - // TODO(jcollins-g): calling dispose() sometimes prevents - // --pause-isolates-on-exit from working; fix. - return analysisServer.server - .shutdown() - .timeout(const Duration(seconds: 1)) - // At runtime, it appears that [ServerDomain.shutdown] returns a - // `Future>`. - .catchError((_) => {}); + Future shutdown() async { + await analysisServer.server.shutdown().timeout(const Duration(seconds: 1)); } Future _completeImpl( Map sources, String sourceName, int offset) async { - sources = _getOverlayMapWithPaths(sources); - await _loadSources(sources); + await _loadSources(_getOverlayMapWithPaths(sources)); - try { - return await analysisServer.completion.getSuggestions2( - _getPathFromName(sourceName), - offset, - 500, - ); - } finally { - // TODO: Remove the need to unload sources. - await _unloadSources(); - } + return await analysisServer.completion.getSuggestions2( + _getPathFromName(sourceName), + offset, + 500, + ); } Future _formatImpl(String src, int? offset) async { await _loadSources({mainPath: src}); - final FormatResult result; - try { - result = await analysisServer.edit.format(mainPath, offset ?? 0, 0); - } finally { - await _unloadSources(); - } - return result; + return await analysisServer.edit.format(mainPath, offset ?? 0, 0); } Map _getOverlayMapWithPaths(Map overlay) { @@ -435,50 +381,27 @@ class DartAnalysisServerWrapper { String _getPathFromName(String sourceName) => path.join(projectPath, sourceName); - final Set _overlayPaths = {}; + List _overlayPaths = []; /// Loads [sources] as file system overlays to the analysis server. /// /// The analysis server then begins to analyze these as priority files. Future _loadSources(Map sources) async { - if (_overlayPaths.isNotEmpty) { - throw StateError( - 'There should be no overlay paths while loading sources, but we ' - 'have: $_overlayPaths'); - } - await _sendAddOverlays(sources); - await analysisServer.analysis.setPriorityFiles(sources.keys.toList()); - } - - Future _unloadSources() async { - await _sendRemoveOverlays(); - await analysisServer.analysis.setPriorityFiles([]); - } - - /// Sends [overlays] to the analysis server. - Future _sendAddOverlays(Map overlays) async { - final contentOverlays = overlays.map((overlayPath, content) => - MapEntry(overlayPath, AddContentOverlay(content))); - - _logger.fine('About to send analysis.updateContent'); - _logger.fine(' ${contentOverlays.keys}'); - - _overlayPaths.addAll(contentOverlays.keys); - - await analysisServer.analysis.updateContent(contentOverlays); - } - - Future _sendRemoveOverlays() async { - _logger.fine('About to send analysis.updateContent remove overlays:'); - _logger.fine(' $_overlayPaths'); - - final contentOverlays = { + // Remove all the existing overlays. + final contentOverlays = { for (final overlayPath in _overlayPaths) overlayPath: RemoveContentOverlay() }; - _overlayPaths.clear(); + + // Add (or replace) new overlays for the given files. + for (final sourceEntry in sources.entries) { + contentOverlays[sourceEntry.key] = AddContentOverlay(sourceEntry.value); + } await analysisServer.analysis.updateContent(contentOverlays); + await analysisServer.analysis.setPriorityFiles(sources.keys.toList()); + + _overlayPaths = sources.keys.toList(); } final Map> _completionCompleters = diff --git a/pkgs/dart_services/lib/src/common_server.dart b/pkgs/dart_services/lib/src/common_server.dart index d721d7fbf..929ea0699 100644 --- a/pkgs/dart_services/lib/src/common_server.dart +++ b/pkgs/dart_services/lib/src/common_server.dart @@ -34,8 +34,8 @@ class CommonServerImpl { final ServerCache cache; final String storageBucket; + late Analyzer analyzer; late Compiler compiler; - late AnalyzerWrapper analysisServer; CommonServerImpl( this.sdk, @@ -46,10 +46,10 @@ class CommonServerImpl { Future init() async { log.fine('initing CommonServerImpl'); - compiler = Compiler(sdk, storageBucket: storageBucket); + analyzer = Analyzer(sdk); + await analyzer.init(); - analysisServer = AnalyzerWrapper(sdk.dartSdkPath); - await analysisServer.init(); + compiler = Compiler(sdk, storageBucket: storageBucket); } Future shutdown() async { @@ -57,7 +57,7 @@ class CommonServerImpl { await cache.shutdown(); - await analysisServer.shutdown(); + await analyzer.shutdown(); await compiler.dispose(); } } @@ -83,7 +83,7 @@ class CommonServerApi { api.SourceRequest.fromJson(await request.readAsJson()); final result = await serialize(() { - return impl.analysisServer.analyze(sourceRequest.source); + return impl.analyzer.analyze(sourceRequest.source); }); return ok(result.toJson()); @@ -139,8 +139,8 @@ class CommonServerApi { final sourceRequest = api.SourceRequest.fromJson(await request.readAsJson()); - final result = await serialize(() => impl.analysisServer - .completeV3(sourceRequest.source, sourceRequest.offset!)); + final result = await serialize(() => + impl.analyzer.completeV3(sourceRequest.source, sourceRequest.offset!)); return ok(result.toJson()); } @@ -152,8 +152,8 @@ class CommonServerApi { final sourceRequest = api.SourceRequest.fromJson(await request.readAsJson()); - final result = await serialize(() => impl.analysisServer - .fixesV3(sourceRequest.source, sourceRequest.offset!)); + final result = await serialize(() => + impl.analyzer.fixesV3(sourceRequest.source, sourceRequest.offset!)); return ok(result.toJson()); } @@ -166,7 +166,7 @@ class CommonServerApi { api.SourceRequest.fromJson(await request.readAsJson()); final result = await serialize(() { - return impl.analysisServer.format( + return impl.analyzer.format( sourceRequest.source, sourceRequest.offset, ); @@ -183,7 +183,7 @@ class CommonServerApi { api.SourceRequest.fromJson(await request.readAsJson()); final result = await serialize(() { - return impl.analysisServer.dartdocV3( + return impl.analyzer.dartdocV3( sourceRequest.source, sourceRequest.offset!, ); diff --git a/pkgs/dart_services/lib/src/project_creator.dart b/pkgs/dart_services/lib/src/project_creator.dart index c11d98cdf..f80feb290 100644 --- a/pkgs/dart_services/lib/src/project_creator.dart +++ b/pkgs/dart_services/lib/src/project_creator.dart @@ -40,7 +40,7 @@ class ProjectCreator { final projectPath = path.join(_templatesPath, 'dart_project'); final projectDirectory = Directory(projectPath); await projectDirectory.create(recursive: true); - final dependencies = _dependencyVersions(supportedBasicDartPackages()); + final dependencies = _dependencyVersions(supportedBasicDartPackages); File(path.join(projectPath, 'pubspec.yaml')) .writeAsStringSync(createPubspec( includeFlutterWeb: false, @@ -91,8 +91,8 @@ ${_sdk.experiments.map((experiment) => ' - $experiment').join('\n')} await Directory(path.join(projectPath, 'web')).create(); await File(path.join(projectPath, 'web', 'index.html')).create(); var packages = { - ...supportedBasicDartPackages(), - ...supportedFlutterPackages(), + ...supportedBasicDartPackages, + ...supportedFlutterPackages, if (firebaseStyle != FirebaseStyle.none) ...coreFirebasePackages, if (firebaseStyle == FirebaseStyle.flutterFire) ...registerableFirebasePackages, @@ -127,8 +127,8 @@ ${_sdk.experiments.map((experiment) => ' - $experiment').join('\n')} // configured in JavaScript, before executing Dart. Now add the full set of // supported Firebase pacakges. This workaround is a very fragile hack. packages = { - ...supportedBasicDartPackages(), - ...supportedFlutterPackages(), + ...supportedBasicDartPackages, + ...supportedFlutterPackages, ...firebasePackages, }; final dependencies = _dependencyVersions(packages); diff --git a/pkgs/dart_services/lib/src/project_templates.dart b/pkgs/dart_services/lib/src/project_templates.dart index 091133d98..d8ab36374 100644 --- a/pkgs/dart_services/lib/src/project_templates.dart +++ b/pkgs/dart_services/lib/src/project_templates.dart @@ -76,74 +76,74 @@ const Set firebasePackages = { }; /// The set of supported Flutter-oriented packages. -Set supportedFlutterPackages() => { - 'animations', - 'creator', - 'firebase_analytics', - 'firebase_database', - 'firebase_messaging', - 'firebase_storage', - 'flame', - 'flame_fire_atlas', - 'flame_forge2d', - 'flame_splash_screen', - 'flame_tiled', - 'flutter_adaptive_scaffold', - 'flutter_bloc', - 'flutter_hooks', - 'flutter_lints', - 'flutter_map', - 'flutter_processing', - 'flutter_riverpod', - 'flutter_svg', - 'go_router', - 'google_fonts', - 'hooks_riverpod', - 'provider', - 'riverpod_navigator', - 'shared_preferences', - 'video_player', - }; +const Set supportedFlutterPackages = { + 'animations', + 'creator', + 'firebase_analytics', + 'firebase_database', + 'firebase_messaging', + 'firebase_storage', + 'flame', + 'flame_fire_atlas', + 'flame_forge2d', + 'flame_splash_screen', + 'flame_tiled', + 'flutter_adaptive_scaffold', + 'flutter_bloc', + 'flutter_hooks', + 'flutter_lints', + 'flutter_map', + 'flutter_processing', + 'flutter_riverpod', + 'flutter_svg', + 'go_router', + 'google_fonts', + 'hooks_riverpod', + 'provider', + 'riverpod_navigator', + 'shared_preferences', + 'video_player', +}; /// The set of packages which indicate that Flutter Web is being used. -Set _packagesIndicatingFlutter() => { - 'flutter', - 'flutter_test', - ...supportedFlutterPackages(), - ...firebasePackages, - }; +const Set _packagesIndicatingFlutter = { + 'flutter', + 'flutter_test', + ...supportedFlutterPackages, + ...firebasePackages, +}; /// The set of basic Dart (non-Flutter) packages which can be directly imported /// into a script. -Set supportedBasicDartPackages() => { - 'basics', - 'bloc', - 'characters', - 'collection', - 'cross_file', - 'dartz', - 'english_words', - 'equatable', - 'fast_immutable_collections', - 'http', - 'intl', - 'js', - 'lints', - 'matcher', - 'meta', - 'path', - 'petitparser', - 'quiver', - 'riverpod', - 'rohd', - 'rohd_vf', - 'rxdart', - 'timezone', - 'tuple', - 'vector_math', - 'yaml', - 'yaml_edit', - }; +const Set supportedBasicDartPackages = { + 'basics', + 'bloc', + 'characters', + 'collection', + 'cross_file', + 'dartz', + 'english_words', + 'equatable', + 'fast_immutable_collections', + 'http', + 'intl', + 'js', + 'lints', + 'matcher', + 'meta', + 'path', + 'petitparser', + 'quiver', + 'riverpod', + 'rohd', + 'rohd_vf', + 'rxdart', + 'timezone', + 'tuple', + 'vector_math', + 'yaml', + 'yaml_edit', +}; /// A set of all allowed `dart:` imports. Currently includes non-VM libraries /// listed as the [doc](https://api.dart.dev/stable/index.html) categories. @@ -174,7 +174,7 @@ bool usesFlutterWeb(Iterable imports) { final packageName = _packageNameFromPackageUri(uriString); return packageName != null && - _packagesIndicatingFlutter().contains(packageName); + _packagesIndicatingFlutter.contains(packageName); }); } @@ -218,10 +218,12 @@ List getUnsupportedImports( if (uriString == null || uriString.isEmpty) { return false; } + // All non-VM 'dart:' imports are ok. if (uriString.startsWith('dart:')) { return !_allowedDartImports.contains(uriString); } + // Filenames from within this compilation files={} sources file set // are OK. (These filenames have been sanitized to prevent 'package:' // (and other) prefixes, so the a filename cannot be used to bypass @@ -245,6 +247,7 @@ List getUnsupportedImports( }).toList(); } -bool isSupportedPackage(String package) => - _packagesIndicatingFlutter().contains(package) || - supportedBasicDartPackages().contains(package); +bool isSupportedPackage(String package) { + return _packagesIndicatingFlutter.contains(package) || + supportedBasicDartPackages.contains(package); +} diff --git a/pkgs/dart_services/lib/src/pub.dart b/pkgs/dart_services/lib/src/pub.dart index b61fbe8d0..cba93782a 100644 --- a/pkgs/dart_services/lib/src/pub.dart +++ b/pkgs/dart_services/lib/src/pub.dart @@ -29,12 +29,11 @@ const _flutterPackages = [ /// This is expensive to calculate; they require reading from disk. /// None of them changes during execution. -final Map _nullSafePackageVersions = - packageVersionsFromPubspecLock( - project.ProjectTemplates.projectTemplates.firebasePath); +final Map _packageVersions = packageVersionsFromPubspecLock( + project.ProjectTemplates.projectTemplates.firebasePath); /// Returns a mapping of Pub package name to package version. -Map getPackageVersions() => _nullSafePackageVersions; +Map getPackageVersions() => _packageVersions; /// Returns a mapping of Pub package name to package version, retrieving data /// from the project template's `pubspec.lock` file. diff --git a/pkgs/dart_services/lib/src/sdk.dart b/pkgs/dart_services/lib/src/sdk.dart index b17860869..033afab37 100644 --- a/pkgs/dart_services/lib/src/sdk.dart +++ b/pkgs/dart_services/lib/src/sdk.dart @@ -52,7 +52,15 @@ class Sdk { final dartSdk = path.dirname(path.dirname(dart)); final flutterSdk = path.dirname(path.dirname(path.dirname(dartSdk))); - // todo: verify that this is a flutter sdk + // Verify that this is a flutter sdk; check for bin/, packages/, and + // packages/flutter/. + final packages = path.join(flutterSdk, 'packages'); + if (!FileSystemEntity.isDirectorySync(flutterSdk) || + !FileSystemEntity.isDirectorySync(path.join(flutterSdk, 'bin')) || + !FileSystemEntity.isDirectorySync(packages) || + !FileSystemEntity.isDirectorySync(path.join(packages, 'flutter'))) { + throw StateError('flutter sdk not found (from $dartSdk)'); + } return flutterSdk; } diff --git a/pkgs/dart_services/pubspec.yaml b/pkgs/dart_services/pubspec.yaml index 67e4b9344..07ecbe441 100644 --- a/pkgs/dart_services/pubspec.yaml +++ b/pkgs/dart_services/pubspec.yaml @@ -1,4 +1,5 @@ name: dart_services +description: The backend service for DartPad. publish_to: none environment: @@ -33,6 +34,3 @@ dev_dependencies: synchronized: ^3.1.0 test: ^1.24.3 test_descriptor: ^2.0.1 - -executables: - services: null diff --git a/pkgs/dart_services/test/analysis_test.dart b/pkgs/dart_services/test/analysis_test.dart index d057eba75..14985f950 100644 --- a/pkgs/dart_services/test/analysis_test.dart +++ b/pkgs/dart_services/test/analysis_test.dart @@ -14,10 +14,10 @@ void main() => defineTests(); void defineTests() { group('analysis', () { final sdk = Sdk(); - late DartAnalysisServerWrapper analysisServer; + late AnalysisServerWrapper analysisServer; setUpAll(() async { - analysisServer = DartAnalysisServerWrapper(sdkPath: sdk.dartSdkPath); + analysisServer = AnalysisServerWrapper(sdkPath: sdk.dartSdkPath); await analysisServer.init(); }); @@ -46,7 +46,7 @@ void defineTests() { expect(issue.code, 'prefer_typing_uninitialized_variables'); }); - test('repro #126 - completions polluted on second request', () async { + test('completions polluted on second request (repro #126)', () async { // https://github.com/dart-lang/dart-services/issues/126 return analysisServer .completeV3(completionFilterCode, 17) @@ -62,7 +62,7 @@ void defineTests() { }); }); - test('import_test', () async { + test('disallow path imports', () async { // We're testing here that we don't have any path imports - we don't want // to enable browsing the file system. final testCode = "import '/'; main() { int a = 0; a. }"; @@ -103,7 +103,7 @@ void defineTests() { expect(completionsContains(results, 'abs'), true); }); - test('simple_quickFix', () async { + test('quickFix simple', () async { final results = await analysisServer.fixesV3(quickFixesCode, 25); final changes = results.fixes; @@ -118,7 +118,7 @@ void defineTests() { changes.map((e) => e.edits.first.replacement), contains(equals(';'))); }); - test('simple_format', () async { + test('format simple', () async { final results = await analysisServer.format(badFormatCode, 0); expect(results.source, formattedCode); }); @@ -170,10 +170,10 @@ void defineTests() { group('analysis flutter', () { final sdk = Sdk(); - late DartAnalysisServerWrapper analysisServer; + late AnalysisServerWrapper analysisServer; setUpAll(() async { - analysisServer = DartAnalysisServerWrapper(sdkPath: sdk.dartSdkPath); + analysisServer = AnalysisServerWrapper(sdkPath: sdk.dartSdkPath); await analysisServer.init(); }); diff --git a/pkgs/dart_services/test/caching_test.dart b/pkgs/dart_services/test/caching_test.dart index c1170be2f..b0371fa8f 100644 --- a/pkgs/dart_services/test/caching_test.dart +++ b/pkgs/dart_services/test/caching_test.dart @@ -11,8 +11,6 @@ import 'package:logging/logging.dart'; import 'package:synchronized/synchronized.dart'; import 'package:test/test.dart'; -// todo: move this away from using a log for testing - void main() async { final hasRedis = await hasRedisServer(); defineTests(hasRedis); diff --git a/pkgs/dart_services/tool/grind.dart b/pkgs/dart_services/tool/grind.dart index 1a4212814..c56cde137 100644 --- a/pkgs/dart_services/tool/grind.dart +++ b/pkgs/dart_services/tool/grind.dart @@ -302,8 +302,8 @@ Future _updateDependenciesFile({ 'lints': 'any', 'flutter_lints': 'any', for (final package in firebasePackages) package: 'any', - for (final package in supportedFlutterPackages()) package: 'any', - for (final package in supportedBasicDartPackages()) package: 'any', + for (final package in supportedFlutterPackages) package: 'any', + for (final package in supportedBasicDartPackages) package: 'any', }; // Overwrite with important constraints. From 0686c8da9625f93189d6888157f90f86a7f4be36 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Sat, 18 Nov 2023 15:51:09 -0800 Subject: [PATCH 3/5] add pubspec lock file to the linguist generated file --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index afd6862a0..c4c287515 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ +**/pubspec.lock linguist-generated=true pkgs/dart_services/lib/src/shared/** linguist-generated=true pkgs/sketch_pad/lib/samples.g.dart linguist-generated=true pkgs/sketch_pad/web/codemirror/** linguist-generated=true From b6d0410e6e8fd48e082ff48212fba7194553a460 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Wed, 22 Nov 2023 09:13:42 -0800 Subject: [PATCH 4/5] review comments --- pkgs/dart_services/lib/src/sdk.dart | 51 +++++++++++++---------------- pkgs/dart_services/tool/grind.dart | 3 +- pkgs/sketch_pad/lib/model.dart | 2 +- 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/pkgs/dart_services/lib/src/sdk.dart b/pkgs/dart_services/lib/src/sdk.dart index 033afab37..d5da18efd 100644 --- a/pkgs/dart_services/lib/src/sdk.dart +++ b/pkgs/dart_services/lib/src/sdk.dart @@ -8,23 +8,24 @@ import 'dart:io'; import 'package:path/path.dart' as path; class Sdk { + /// The path to the Dart SDK (vended into the Flutter SDK). + late final String dartSdkPath; + + /// The path to the Flutter SDK. + late final String flutterSdkPath; + /// The path to the Flutter binaries. late final String _flutterBinPath; - /// The path to the Dart SDK. - late final String dartSdkPath; - - /// The current version of the SDK, including any `-dev` suffix. + /// The current version of the Dart SDK, including any `-dev` suffix. late final String dartVersion; + /// The current version of the Flutter SDK. late final String flutterVersion; - /// The current version of the Flutter engine + /// The current version of the Flutter engine. late final String engineVersion; - /// The current version of the SDK, not including any `-dev` suffix. - late final String version; - // The channel for this SDK. late final String channel; @@ -37,44 +38,36 @@ class Sdk { /// If this is the main channel. bool get mainChannel => channel == 'main'; - // The directory that contains this SDK - String? _sdkPath; - /// Experiments that this SDK is configured with List get experiments { if (mainChannel) return const ['inline-class']; return const []; } - String _getSdkPath() { + void _initPaths() { // /bin/cache/dart-sdk - final dart = Platform.resolvedExecutable; - final dartSdk = path.dirname(path.dirname(dart)); - final flutterSdk = path.dirname(path.dirname(path.dirname(dartSdk))); + final dartVM = Platform.resolvedExecutable; + + dartSdkPath = path.dirname(path.dirname(dartVM)); + flutterSdkPath = path.dirname(path.dirname(path.dirname(dartSdkPath))); + _flutterBinPath = path.join(flutterSdkPath, 'bin'); // Verify that this is a flutter sdk; check for bin/, packages/, and // packages/flutter/. - final packages = path.join(flutterSdk, 'packages'); - if (!FileSystemEntity.isDirectorySync(flutterSdk) || - !FileSystemEntity.isDirectorySync(path.join(flutterSdk, 'bin')) || + final packages = path.join(flutterSdkPath, 'packages'); + if (!FileSystemEntity.isDirectorySync(flutterSdkPath) || + !FileSystemEntity.isDirectorySync(path.join(flutterSdkPath, 'bin')) || !FileSystemEntity.isDirectorySync(packages) || !FileSystemEntity.isDirectorySync(path.join(packages, 'flutter'))) { - throw StateError('flutter sdk not found (from $dartSdk)'); + throw StateError('flutter sdk not found (from $dartSdkPath)'); } - - return flutterSdk; } - String get sdkPath => _sdkPath ??= _getSdkPath(); - Sdk() { - _flutterBinPath = path.join(sdkPath, 'bin'); + _initPaths(); dartSdkPath = path.join(_flutterBinPath, 'cache', 'dart-sdk'); dartVersion = _readVersionFile(dartSdkPath); - version = dartVersion.contains('-') - ? dartVersion.substring(0, dartVersion.indexOf('-')) - : dartVersion; // flutter --version --machine final versions = _callFlutterVersion(); @@ -116,13 +109,13 @@ class Sdk { return jsonDecode(Process.runSync( flutterToolPath, ['--version', '--machine'], - workingDirectory: sdkPath, + workingDirectory: flutterSdkPath, ).stdout.toString().trim()) as Map; } on FormatException { return jsonDecode(Process.runSync( flutterToolPath, ['--version', '--machine'], - workingDirectory: sdkPath, + workingDirectory: flutterSdkPath, ).stdout.toString().trim()) as Map; } } diff --git a/pkgs/dart_services/tool/grind.dart b/pkgs/dart_services/tool/grind.dart index c56cde137..2c0c1aba3 100644 --- a/pkgs/dart_services/tool/grind.dart +++ b/pkgs/dart_services/tool/grind.dart @@ -48,7 +48,8 @@ void validateStorageArtifacts() async { false => 'nnbd_artifacts', }; - print('validate-storage-artifacts version: ${sdk.version} bucket: $bucket'); + print( + 'validate-storage-artifacts version: ${sdk.dartVersion} bucket: $bucket'); final urlBase = 'https://storage.googleapis.com/$bucket/'; for (final artifact in compilationArtifacts) { diff --git a/pkgs/sketch_pad/lib/model.dart b/pkgs/sketch_pad/lib/model.dart index 6721a736e..287f038c4 100644 --- a/pkgs/sketch_pad/lib/model.dart +++ b/pkgs/sketch_pad/lib/model.dart @@ -356,7 +356,7 @@ enum Channel { const Channel(this.displayName, this.url); - static const defaultChannel = Channel.localhost; + static const defaultChannel = Channel.stable; static List get valuesWithoutLocalhost { return values.whereNot((channel) => channel == localhost).toList(); From 634cf86e1b6b81cbc49782f82600ec37d4119bf0 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Wed, 22 Nov 2023 09:29:59 -0800 Subject: [PATCH 5/5] fix a late init error --- pkgs/dart_services/lib/src/sdk.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/dart_services/lib/src/sdk.dart b/pkgs/dart_services/lib/src/sdk.dart index d5da18efd..e8f8c9a64 100644 --- a/pkgs/dart_services/lib/src/sdk.dart +++ b/pkgs/dart_services/lib/src/sdk.dart @@ -66,7 +66,6 @@ class Sdk { Sdk() { _initPaths(); - dartSdkPath = path.join(_flutterBinPath, 'cache', 'dart-sdk'); dartVersion = _readVersionFile(dartSdkPath); // flutter --version --machine