mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 13:18:01 +00:00
Remove the obsolete dartfix package
Change-Id: Icc986d6345e2867ca0f3e3863dff6b0418db8242 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169761 Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Devon Carew <devoncarew@google.com>
This commit is contained in:
parent
5efe55abf7
commit
224a997a23
|
@ -228,12 +228,6 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "2.10"
|
||||
},
|
||||
{
|
||||
"name": "dartfix",
|
||||
"rootUri": "../pkg/dartfix",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.8"
|
||||
},
|
||||
{
|
||||
"name": "dds",
|
||||
"rootUri": "../pkg/dds",
|
||||
|
|
|
@ -35,7 +35,6 @@ dart_internal:pkg/dart_internal/lib
|
|||
dart_style:third_party/pkg_tested/dart_style/lib
|
||||
dartdev:pkg/dartdev/lib
|
||||
dartdoc:third_party/pkg/dartdoc/lib
|
||||
dartfix:pkg/dartfix/lib
|
||||
dds:pkg/dds/lib
|
||||
dev_compiler:pkg/dev_compiler/lib
|
||||
diagnostic:pkg/diagnostic/lib
|
||||
|
|
4
pkg/dartfix/.gitignore
vendored
4
pkg/dartfix/.gitignore
vendored
|
@ -1,4 +0,0 @@
|
|||
*.iml
|
||||
.dart_tool
|
||||
.packages
|
||||
pubspec.lock
|
|
@ -1,38 +0,0 @@
|
|||
# 0.1.8
|
||||
* The dartfix package has been deprecated. The functionality has been moved to
|
||||
the new `dart fix` command that's included in the SDK.
|
||||
|
||||
# 0.1.7
|
||||
* Improve experimental non-nullable migration support.
|
||||
* Extract some nnbd migration implementation components from the dartfix
|
||||
package.
|
||||
|
||||
# 0.1.6
|
||||
* Improve experimental non-nullable migration support.
|
||||
|
||||
# 0.1.5
|
||||
* Add command line options for selecting/excluding fixes to apply (`--fix`,
|
||||
`--excludeFix`, and `--required`). Call with `--help` for more details.
|
||||
* Add a `--color` option for printing messages with ANSI colors. This defaults
|
||||
to true if the terminal supports ANSI colors.
|
||||
* Add a `--pedantic` option for specifying fixes relating to the [pedantic]
|
||||
lints.
|
||||
* Add experimental non-nullable migration support.
|
||||
|
||||
[pedantic]: https://pub.dev/packages/pedantic
|
||||
|
||||
# 0.1.4
|
||||
* update protocol version constraints
|
||||
|
||||
# 0.1.3
|
||||
* update SDK constraints
|
||||
|
||||
# 0.1.2
|
||||
* update SDK constraints
|
||||
* add example.dart showing what can be "fixed"
|
||||
|
||||
# 0.1.1
|
||||
* Remove reading dartfix version from pubspec
|
||||
|
||||
# 0.1.0
|
||||
* Initial version
|
|
@ -1,26 +0,0 @@
|
|||
Copyright 2018, the Dart project authors. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,82 +0,0 @@
|
|||
`dartfix` is a command-line tool for migrating your Dart code
|
||||
to use newer syntax styles.
|
||||
|
||||
## Usage
|
||||
|
||||
> **Important:**
|
||||
> Save a copy of your source code before making changes with `dartfix`.
|
||||
> Unlike [dartfmt][], which makes only safe changes (usually to whitespace),
|
||||
> `dartfix` can make changes that you might need to undo or modify.
|
||||
|
||||
Before you can use the `dartfix` tool, you need to
|
||||
[install it](#installing-and-updating-dartfix), as described below.
|
||||
Then invoke it with the name of the directory that you want to update.
|
||||
When you're ready to make the suggested changes,
|
||||
add the `--overwrite` option.
|
||||
|
||||
```terminal
|
||||
$ dartfix examples/misc
|
||||
... summary of recommended changes ...
|
||||
$ dartfix examples/misc --overwrite
|
||||
```
|
||||
|
||||
## Features
|
||||
`dartfix` applies different types of "fixes" to migrate your Dart code.
|
||||
By default, all fixes are applied, but you can select only the specific fixes you
|
||||
want. See `dartfix --help` for more about the available command line options.
|
||||
|
||||
Some of the fixes that you can apply are "required" in that the Dart language
|
||||
is changing and at some point the old syntax will no longer be supported.
|
||||
To only apply these changes, pass the `--required` option on the command line.
|
||||
The required fixes include:
|
||||
|
||||
* Find classes used as mixins, and convert them to use the `mixin` keyword
|
||||
instead of `class`.
|
||||
Mixin support is one of the [features added to Dart in 2.1][].
|
||||
At some point in the future, the Dart team plans
|
||||
to disallow using classes as mixins.
|
||||
|
||||
* Move named constructor type arguments from the name to the type. <br>
|
||||
For example, given `class A<T> { A.from(Object obj) { } }`,
|
||||
`dartfix` changes constructor invocations in the following way:
|
||||
|
||||
```
|
||||
Original code:
|
||||
A.from<String>(anObject) // Invokes the `A.from` named constructor.
|
||||
|
||||
Code produced by dartfix:
|
||||
A<String>.from(anObject) // Same, but the type is directly after `A`.
|
||||
```
|
||||
|
||||
Other changes are recommended but not required. These include:
|
||||
|
||||
* Find `double` literals that end in `.0`, and remove the `.0`.
|
||||
Language support for this was [added in Dart in 2.1][].
|
||||
|
||||
## Installing and updating dartfix
|
||||
|
||||
The easiest way to use `dartfix` is to [globally install][] it,
|
||||
so that it can be [in your path][PATH]:
|
||||
|
||||
```terminal
|
||||
$ pub global activate dartfix
|
||||
```
|
||||
|
||||
Use the same command to update `dartfix`.
|
||||
We recommend updating `dartfix` whenever you update your Dart SDK
|
||||
or when a new feature is released.
|
||||
|
||||
## Filing issues
|
||||
|
||||
If you want a new fix, first look at [dartfix issues][]
|
||||
and star the fixes you want.
|
||||
If no issue exists for the fix, [create a GitHub issue.][new issue]
|
||||
|
||||
[dartfix]: https://pub.dev/packages/dartfix
|
||||
[dartfmt]: https://dart.dev/tools/dartfmt
|
||||
[added in Dart in 2.1]: https://github.com/dart-lang/sdk/blob/master/CHANGELOG.md#210---2018-11-15
|
||||
[features added to Dart in 2.1]: https://github.com/dart-lang/sdk/blob/master/CHANGELOG.md#210---2018-11-15
|
||||
[globally install]: https://dart.dev/tools/pub/cmd/pub-global
|
||||
[new issue]: https://github.com/dart-lang/sdk/issues/new?title=dartfix%20request%3A%20%3CSUMMARIZE%20REQUEST%20HERE%3E
|
||||
[dartfix issues]: https://github.com/dart-lang/sdk/issues?q=is%3Aissue+is%3Aopen+label%3Aanalyzer-dartfix
|
||||
[PATH]: https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path
|
|
@ -1,42 +0,0 @@
|
|||
include: package:pedantic/analysis_options.1.8.0.yaml
|
||||
|
||||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
||||
errors:
|
||||
# Increase the severity of the unused_import hint.
|
||||
unused_import: warning
|
||||
unnecessary_brace_in_string_interps: warning
|
||||
# There are many pre-existing violations; this lint may not work well with
|
||||
# the Analyzer team's style.
|
||||
omit_local_variable_types: ignore
|
||||
# Turn off the prefer_is_empty lint so that it can be used in the example tests
|
||||
# and not be reported during normal package analysis.
|
||||
prefer_is_empty: ignore
|
||||
|
||||
linter:
|
||||
rules:
|
||||
- await_only_futures
|
||||
- directives_ordering
|
||||
- empty_statements
|
||||
- unnecessary_brace_in_string_interps
|
||||
#
|
||||
# Delta from pedantic 1.8.0 to 1.9.0
|
||||
#
|
||||
#- always_declare_return_types # 17
|
||||
- always_require_non_null_named_parameters
|
||||
- annotate_overrides
|
||||
- avoid_null_checks_in_equality_operators
|
||||
- camel_case_extensions
|
||||
#- omit_local_variable_types # 44
|
||||
- prefer_adjacent_string_concatenation
|
||||
- prefer_collection_literals
|
||||
- prefer_conditional_assignment
|
||||
#- prefer_final_fields # 1
|
||||
- prefer_for_elements_to_map_fromIterable
|
||||
- prefer_generic_function_type_aliases
|
||||
#- prefer_if_null_operators # 2
|
||||
- prefer_single_quotes
|
||||
- prefer_spread_collections
|
||||
- unnecessary_this
|
||||
- use_function_type_syntax_for_parameters
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env dart
|
||||
// Copyright (c) 2018, 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:dartfix/src/driver.dart';
|
||||
|
||||
/// The entry point for dartfix.
|
||||
void main(List<String> args) async {
|
||||
Driver starter = Driver();
|
||||
|
||||
// Wait for the starter to complete.
|
||||
await starter.start(args);
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2019, 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.
|
||||
|
||||
// This file contains code that is modified by running dartfix.
|
||||
// After running dartfix, this content matches a file in the "fixed" directory.
|
||||
|
||||
// Dart will automatically convert int literals to doubles.
|
||||
// Running dartfix converts this double literal to an int
|
||||
// if --double-to-int is specified on the command line.
|
||||
const double myDouble = 4.0;
|
||||
|
||||
// This class is used as a mixin but does not use the new mixin syntax.
|
||||
// Running dartfix converts this class to use the new syntax.
|
||||
class MyMixin {
|
||||
final someValue = myDouble;
|
||||
}
|
||||
|
||||
class MyClass with MyMixin {}
|
||||
|
||||
void main(List<String> args) {
|
||||
if (args.length == 0) {
|
||||
print('myDouble = ${MyClass().someValue}');
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2019, 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.
|
||||
|
||||
// This file contains code that has been modified by running dartfix.
|
||||
// See example.dart for the original unmodified code.
|
||||
|
||||
// Dart will automatically convert int literals to doubles.
|
||||
// Running dartfix converts this double literal to an int
|
||||
// if --double-to-int is specified on the command line.
|
||||
const double myDouble = 4;
|
||||
|
||||
// This class is used as a mixin but does not use the new mixin syntax.
|
||||
// Running dartfix converts this class to use the new syntax.
|
||||
mixin MyMixin {
|
||||
final someValue = myDouble;
|
||||
}
|
||||
|
||||
class MyClass with MyMixin {}
|
||||
|
||||
void main(List<String> args) {
|
||||
if (args.length == 0) {
|
||||
print('myDouble = ${MyClass().someValue}');
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2019, 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.
|
||||
|
||||
// This file contains code that has been modified by running dartfix.
|
||||
// See example.dart for the original unmodified code.
|
||||
|
||||
// Dart will automatically convert int literals to doubles.
|
||||
// Running dartfix converts this double literal to an int
|
||||
// if --double-to-int is specified on the command line.
|
||||
const double myDouble = 4.0;
|
||||
|
||||
// This class is used as a mixin but does not use the new mixin syntax.
|
||||
// Running dartfix converts this class to use the new syntax.
|
||||
class MyMixin {
|
||||
final someValue = myDouble;
|
||||
}
|
||||
|
||||
class MyClass with MyMixin {}
|
||||
|
||||
void main(List<String> args) {
|
||||
if (args.isEmpty) {
|
||||
print('myDouble = ${MyClass().someValue}');
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2019, 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.
|
||||
|
||||
// This file contains code that has been modified by running dartfix.
|
||||
// See example.dart for the original unmodified code.
|
||||
|
||||
// Dart will automatically convert int literals to doubles.
|
||||
// Running dartfix converts this double literal to an int
|
||||
// if --double-to-int is specified on the command line.
|
||||
const double myDouble = 4.0;
|
||||
|
||||
// This class is used as a mixin but does not use the new mixin syntax.
|
||||
// Running dartfix converts this class to use the new syntax.
|
||||
class MyMixin {
|
||||
final someValue = myDouble;
|
||||
}
|
||||
|
||||
class MyClass with MyMixin {}
|
||||
|
||||
void main(List<String> args) {
|
||||
if (args.isEmpty) {
|
||||
print('myDouble = ${MyClass().someValue}');
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2019, 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.
|
||||
|
||||
// This file contains code that has been modified by running dartfix.
|
||||
// See example.dart for the original unmodified code.
|
||||
|
||||
// Dart will automatically convert int literals to doubles.
|
||||
// Running dartfix converts this double literal to an int
|
||||
// if --double-to-int is specified on the command line.
|
||||
const double myDouble = 4.0;
|
||||
|
||||
// This class is used as a mixin but does not use the new mixin syntax.
|
||||
// Running dartfix converts this class to use the new syntax.
|
||||
mixin MyMixin {
|
||||
final someValue = myDouble;
|
||||
}
|
||||
|
||||
class MyClass with MyMixin {}
|
||||
|
||||
void main(List<String> args) {
|
||||
if (args.length == 0) {
|
||||
print('myDouble = ${MyClass().someValue}');
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright (c) 2018, 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.
|
||||
//
|
||||
// This file has been automatically generated. Please do not edit it manually.
|
||||
// To regenerate the file, use the script
|
||||
// "pkg/analysis_server/tool/spec/generate_files".
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analysis_server_client/handler/notification_handler.dart';
|
||||
import 'package:analysis_server_client/protocol.dart';
|
||||
|
||||
/// [AnalysisCompleteHandler] listens to analysis server notifications
|
||||
/// and detects when analysis has finished.
|
||||
mixin AnalysisCompleteHandler on NotificationHandler {
|
||||
Completer<void> _analysisComplete;
|
||||
|
||||
@override
|
||||
void onServerStatus(ServerStatusParams params) {
|
||||
if (params.analysis != null && !params.analysis.isAnalyzing) {
|
||||
_analysisComplete?.complete();
|
||||
_analysisComplete = null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> analysisComplete() {
|
||||
_analysisComplete ??= Completer<void>();
|
||||
return _analysisComplete.future;
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (c) 2018, 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:analysis_server_client/listener/server_listener.dart';
|
||||
|
||||
/// [BadMessageListener] throws an exception if the [Client] receives bad data.
|
||||
mixin BadMessageListener on ServerListener {
|
||||
/// True if we've received bad data from the server.
|
||||
bool _receivedBadDataFromServer = false;
|
||||
|
||||
void throwDelayedException(String prefix, String details) {
|
||||
if (!_receivedBadDataFromServer) {
|
||||
_receivedBadDataFromServer = true;
|
||||
// Give the server 1 second to continue outputting bad data
|
||||
// such as outputting a stacktrace.
|
||||
Future.delayed(Duration(seconds: 1), () {
|
||||
throw '$prefix $details';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void badMessage(String trimmedLine, exception) {
|
||||
super.badMessage(trimmedLine, exception);
|
||||
throwDelayedException('JSON decode failure', '$exception');
|
||||
}
|
||||
|
||||
@override
|
||||
void errorMessage(String line) {
|
||||
super.errorMessage(line);
|
||||
throwDelayedException('ERR:', line);
|
||||
}
|
||||
|
||||
@override
|
||||
void unexpectedMessage(Map<String, dynamic> message) {
|
||||
super.unexpectedMessage(message);
|
||||
throwDelayedException(
|
||||
'BAD DATA FROM SERVER:', 'Unexpected message from server');
|
||||
}
|
||||
|
||||
@override
|
||||
void unexpectedResponse(Map<String, dynamic> message, id) {
|
||||
super.unexpectedResponse(message, id);
|
||||
throw 'Unexpected response from server: id=$id';
|
||||
}
|
||||
|
||||
@override
|
||||
void unexpectedStop(int exitCode) {
|
||||
super.unexpectedStop(exitCode);
|
||||
throwDelayedException('Server terminated with exit code', '$exitCode');
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright (c) 2018, 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:analysis_server_client/listener/server_listener.dart';
|
||||
import 'package:analysis_server_client/server.dart';
|
||||
import 'package:dartfix/listener/bad_message_listener.dart';
|
||||
import 'package:dartfix/listener/timed_listener.dart';
|
||||
|
||||
/// [RecordingListener] caches all messages exchanged with the server
|
||||
/// and print them if a problem occurs.
|
||||
///
|
||||
/// This is primarily used when testing and debugging the analysis server.
|
||||
class RecordingListener with ServerListener, BadMessageListener, TimedListener {
|
||||
/// True if we are currently printing out messages exchanged with the server.
|
||||
bool _echoMessages = false;
|
||||
|
||||
/// Messages which have been exchanged with the server; we buffer these
|
||||
/// up until the test finishes, so that they can be examined in the debugger
|
||||
/// or printed out in response to a call to [echoMessages].
|
||||
final _messages = <String>[];
|
||||
|
||||
/// Print out any messages exchanged with the server. If some messages have
|
||||
/// already been exchanged with the server, they are printed out immediately.
|
||||
void echoMessages() {
|
||||
if (_echoMessages) {
|
||||
return;
|
||||
}
|
||||
_echoMessages = true;
|
||||
for (String line in _messages) {
|
||||
print(line);
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the [Server] is terminating the server process
|
||||
/// rather than requesting that the server stop itself.
|
||||
@override
|
||||
void killingServerProcess(String reason) {
|
||||
echoMessages();
|
||||
super.killingServerProcess(reason);
|
||||
}
|
||||
|
||||
/// Log a timed message about interaction with the server.
|
||||
@override
|
||||
void logTimed(double elapseTime, String prefix, String details) {
|
||||
String line = '$elapseTime: $prefix $details';
|
||||
if (_echoMessages) {
|
||||
print(line);
|
||||
}
|
||||
_messages.add(line);
|
||||
}
|
||||
|
||||
@override
|
||||
void throwDelayedException(String prefix, String details) {
|
||||
echoMessages();
|
||||
super.throwDelayedException(prefix, details);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright (c) 2018, 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:analysis_server_client/listener/server_listener.dart';
|
||||
|
||||
/// [TimedListener] appends a timestamp (seconds since server startup)
|
||||
/// to each logged interaction with the server.
|
||||
mixin TimedListener on ServerListener {
|
||||
/// Stopwatch that we use to generate timing information for debug output.
|
||||
final Stopwatch _time = Stopwatch();
|
||||
|
||||
/// The [currentElapseTime] at which the last communication was received from
|
||||
/// the server or `null` if no communication has been received.
|
||||
double lastCommunicationTime;
|
||||
|
||||
/// The current elapse time (seconds) since the server was started.
|
||||
double get currentElapseTime => _time.elapsedTicks / _time.frequency;
|
||||
|
||||
@override
|
||||
void log(String prefix, String details) {
|
||||
logTimed(currentElapseTime, prefix, details);
|
||||
}
|
||||
|
||||
/// Log a timed message about interaction with the server.
|
||||
void logTimed(double elapseTime, String prefix, String details);
|
||||
|
||||
@override
|
||||
void messageReceived(String json) {
|
||||
lastCommunicationTime = currentElapseTime;
|
||||
super.messageReceived(json);
|
||||
}
|
||||
|
||||
@override
|
||||
void startingServer(String dartBinary, List<String> arguments) {
|
||||
_time.start();
|
||||
super.startingServer(dartBinary, arguments);
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) 2018, 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' as io;
|
||||
|
||||
/// The context for dartfix.
|
||||
class Context {
|
||||
String get workingDir => io.Directory.current.path;
|
||||
|
||||
bool exists(String filePath) {
|
||||
return io.FileSystemEntity.typeSync(filePath) !=
|
||||
io.FileSystemEntityType.notFound;
|
||||
}
|
||||
|
||||
void exit(int code) {
|
||||
io.exit(code);
|
||||
}
|
||||
|
||||
bool isDirectory(String filePath) {
|
||||
return io.FileSystemEntity.typeSync(filePath) ==
|
||||
io.FileSystemEntityType.directory;
|
||||
}
|
||||
}
|
|
@ -1,508 +0,0 @@
|
|||
// Copyright (c) 2018, 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' show File, Platform;
|
||||
|
||||
import 'package:analysis_server_client/handler/connection_handler.dart';
|
||||
import 'package:analysis_server_client/handler/notification_handler.dart';
|
||||
import 'package:analysis_server_client/listener/server_listener.dart';
|
||||
import 'package:analysis_server_client/protocol.dart';
|
||||
import 'package:analysis_server_client/server.dart';
|
||||
import 'package:cli_util/cli_logging.dart';
|
||||
import 'package:dartfix/handler/analysis_complete_handler.dart';
|
||||
import 'package:dartfix/listener/bad_message_listener.dart';
|
||||
import 'package:dartfix/src/context.dart';
|
||||
import 'package:dartfix/src/options.dart';
|
||||
import 'package:dartfix/src/util.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import 'migrate/display.dart';
|
||||
import 'util.dart';
|
||||
|
||||
class Driver {
|
||||
Context context;
|
||||
_Handler handler;
|
||||
Logger logger;
|
||||
Server server;
|
||||
|
||||
bool force;
|
||||
bool overwrite;
|
||||
List<String> targets;
|
||||
EditDartfixResult result;
|
||||
|
||||
Ansi get ansi => logger.ansi;
|
||||
|
||||
/// Apply the fixes that were computed.
|
||||
void applyFixes() {
|
||||
for (SourceFileEdit fileEdit in result.edits) {
|
||||
final file = File(fileEdit.file);
|
||||
String code = file.existsSync() ? file.readAsStringSync() : '';
|
||||
code = SourceEdit.applySequence(code, fileEdit.edits);
|
||||
file.writeAsStringSync(code);
|
||||
}
|
||||
}
|
||||
|
||||
bool checkIfChangesShouldBeApplied(EditDartfixResult result) {
|
||||
logger.stdout('');
|
||||
if (result.hasErrors) {
|
||||
logger.stdout('WARNING: The analyzed source contains errors'
|
||||
' that might affect the accuracy of these changes.');
|
||||
logger.stdout('');
|
||||
if (!force) {
|
||||
logger.stdout('Rerun with --$forceOption to apply these changes.');
|
||||
return false;
|
||||
}
|
||||
} else if (!overwrite && !force) {
|
||||
logger.stdout('Rerun with --$overwriteOption to apply these changes.');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Check if the specified options is supported by the version of analysis
|
||||
/// server being run and return `true` if they are.
|
||||
/// Display an error message and return `false` if not.
|
||||
bool checkIfSelectedOptionsAreSupported(Options options) {
|
||||
if (handler.serverProtocolVersion.compareTo(Version(1, 27, 2)) >= 0) {
|
||||
return true;
|
||||
}
|
||||
if (options.pedanticFixes) {
|
||||
_unsupportedOption(pedanticOption);
|
||||
return false;
|
||||
}
|
||||
if (handler.serverProtocolVersion.compareTo(Version(1, 22, 2)) >= 0) {
|
||||
return true;
|
||||
}
|
||||
if (options.excludeFixes.isNotEmpty) {
|
||||
_unsupportedOption(excludeFixOption);
|
||||
return false;
|
||||
}
|
||||
if (options.includeFixes.isNotEmpty) {
|
||||
_unsupportedOption(includeFixOption);
|
||||
return false;
|
||||
}
|
||||
if (options.showHelp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void printAndApplyFixes() {
|
||||
showDescriptions('Recommended changes that cannot be automatically applied',
|
||||
result.otherSuggestions);
|
||||
showDetails(result.details);
|
||||
if (result.edits.isEmpty) {
|
||||
logger.stdout('');
|
||||
logger.stdout(result.otherSuggestions.isNotEmpty
|
||||
? 'None of the recommended changes can be automatically applied.'
|
||||
: 'No recommended changes.');
|
||||
return;
|
||||
}
|
||||
logger.stdout('');
|
||||
logger.stdout(ansi.emphasized('Files to be changed:'));
|
||||
for (SourceFileEdit fileEdit in result.edits) {
|
||||
logger.stdout(' ${_relativePath(fileEdit.file)}');
|
||||
}
|
||||
if (checkIfChangesShouldBeApplied(result)) {
|
||||
applyFixes();
|
||||
logger.stdout(ansi.emphasized('Changes have been applied.'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<EditDartfixResult> requestFixes(
|
||||
Options options, {
|
||||
Progress progress,
|
||||
}) async {
|
||||
Future isAnalysisComplete = handler.analysisComplete();
|
||||
|
||||
final params = EditDartfixParams(options.targets);
|
||||
if (options.excludeFixes.isNotEmpty) {
|
||||
params.excludedFixes = options.excludeFixes;
|
||||
}
|
||||
if (options.includeFixes.isNotEmpty) {
|
||||
params.includedFixes = options.includeFixes;
|
||||
}
|
||||
if (options.pedanticFixes) {
|
||||
params.includePedanticFixes = true;
|
||||
}
|
||||
Map<String, dynamic> json =
|
||||
await server.send(EDIT_REQUEST_DARTFIX, params.toJson());
|
||||
|
||||
// TODO(danrubel): This is imprecise signal for determining when all
|
||||
// analysis error notifications have been received. Consider adding a new
|
||||
// notification indicating that the server is idle (all requests processed,
|
||||
// all analysis complete, all notifications sent).
|
||||
await isAnalysisComplete;
|
||||
|
||||
progress.finish(showTiming: true);
|
||||
ResponseDecoder decoder = ResponseDecoder(null);
|
||||
return EditDartfixResult.fromJson(decoder, 'result', json);
|
||||
}
|
||||
|
||||
/// Return `true` if the changes should be applied.
|
||||
bool shouldApplyFixes(EditDartfixResult result) {
|
||||
return overwrite || force;
|
||||
}
|
||||
|
||||
void showDescriptions(String title, List<DartFixSuggestion> suggestions) {
|
||||
if (suggestions.isNotEmpty) {
|
||||
logger.stdout('');
|
||||
logger.stdout(ansi.emphasized('$title:'));
|
||||
List<DartFixSuggestion> sorted = List.from(suggestions)
|
||||
..sort(compareSuggestions);
|
||||
for (DartFixSuggestion suggestion in sorted) {
|
||||
final msg = StringBuffer();
|
||||
msg.write(' ${toSentenceFragment(suggestion.description)}');
|
||||
final loc = suggestion.location;
|
||||
if (loc != null) {
|
||||
msg.write(' • ${_relativePath(loc.file)}');
|
||||
msg.write(' • ${loc.startLine}:${loc.startColumn}');
|
||||
}
|
||||
logger.stdout(msg.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showDetails(List<String> details) {
|
||||
if (details == null || details.isEmpty) {
|
||||
return;
|
||||
}
|
||||
logger.stdout('''
|
||||
|
||||
Analysis Details:
|
||||
''');
|
||||
for (String detail in details) {
|
||||
logger.stdout('''
|
||||
• $detail
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
||||
void showFix(DartFix fix) {
|
||||
logger.stdout('''
|
||||
|
||||
• ${ansi.emphasized(fix.name)}''');
|
||||
if (fix.description != null) {
|
||||
for (String line in _indentAndWrapDescription(fix.description)) {
|
||||
logger.stdout(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<EditGetDartfixInfoResult> showFixes({Progress progress}) async {
|
||||
Map<String, dynamic> json = await server.send(
|
||||
EDIT_REQUEST_GET_DARTFIX_INFO, EditGetDartfixInfoParams().toJson());
|
||||
progress?.finish(showTiming: true);
|
||||
ResponseDecoder decoder = ResponseDecoder(null);
|
||||
final result = EditGetDartfixInfoResult.fromJson(decoder, 'result', json);
|
||||
|
||||
final fixes = List<DartFix>.from(result.fixes)
|
||||
..sort((f1, f2) => f1.name.compareTo(f2.name));
|
||||
|
||||
logger.stdout('''
|
||||
|
||||
These fixes can be enabled using --$includeFixOption:''');
|
||||
|
||||
fixes
|
||||
..sort(compareFixes)
|
||||
..forEach(showFix);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future start(
|
||||
List<String> args, {
|
||||
Context testContext,
|
||||
Logger testLogger,
|
||||
}) async {
|
||||
final Options options = Options.parse(args, testContext, testLogger);
|
||||
|
||||
force = options.force;
|
||||
overwrite = options.overwrite;
|
||||
targets = options.targets;
|
||||
context = testContext ?? options.context;
|
||||
logger = testLogger ?? options.logger;
|
||||
server = Server(listener: _Listener(logger));
|
||||
handler = _Handler(this, context);
|
||||
|
||||
// Start showing progress before we start the analysis server.
|
||||
Progress progress;
|
||||
if (options.showHelp) {
|
||||
progress = logger.progress('${ansi.emphasized('Listing fixes')}');
|
||||
} else {
|
||||
progress = logger.progress('${ansi.emphasized('Calculating fixes')}');
|
||||
}
|
||||
|
||||
if (!await startServer(options)) {
|
||||
context.exit(16);
|
||||
}
|
||||
|
||||
if (!checkIfSelectedOptionsAreSupported(options)) {
|
||||
await server.stop();
|
||||
context.exit(1);
|
||||
}
|
||||
|
||||
if (options.showHelp) {
|
||||
try {
|
||||
await showFixes(progress: progress);
|
||||
} finally {
|
||||
await server.stop();
|
||||
}
|
||||
context.exit(0);
|
||||
}
|
||||
|
||||
if (options.includeFixes.isEmpty && !options.pedanticFixes) {
|
||||
logger.stdout('No fixes specified.');
|
||||
context.exit(1);
|
||||
}
|
||||
|
||||
Future serverStopped;
|
||||
try {
|
||||
await startServerAnalysis(options);
|
||||
result = await requestFixes(options, progress: progress);
|
||||
var fileEdits = result.edits;
|
||||
var editCount = 0;
|
||||
for (SourceFileEdit fileEdit in fileEdits) {
|
||||
editCount += fileEdit.edits.length;
|
||||
}
|
||||
logger.stdout('Found $editCount changes in ${fileEdits.length} files.');
|
||||
|
||||
previewFixes(logger, result);
|
||||
|
||||
//
|
||||
// Stop the server.
|
||||
//
|
||||
serverStopped = server.stop();
|
||||
|
||||
logger.stdout('');
|
||||
|
||||
// Check if we should apply fixes.
|
||||
if (result.edits.isEmpty) {
|
||||
logger.stdout(result.otherSuggestions.isNotEmpty
|
||||
? 'None of the recommended changes can be automatically applied.'
|
||||
: 'There are no recommended changes.');
|
||||
} else if (shouldApplyFixes(result)) {
|
||||
applyFixes();
|
||||
logger.stdout('Changes have been applied.');
|
||||
} else {
|
||||
logger.stdout('Re-run with --overwrite to apply the above changes.');
|
||||
}
|
||||
await serverStopped;
|
||||
} finally {
|
||||
// If we didn't already try to stop the server, then stop it now.
|
||||
if (serverStopped == null) {
|
||||
await server.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> startServer(Options options) async {
|
||||
// Automatically run analysis server from source
|
||||
// if this command line tool is being run from source within the SDK repo.
|
||||
String serverPath = options.serverSnapshot ?? findServerPath();
|
||||
if (options.verbose) {
|
||||
logger.trace('''
|
||||
Dart SDK version ${Platform.version}
|
||||
${Platform.resolvedExecutable}
|
||||
dartfix
|
||||
${Platform.script.toFilePath()}
|
||||
analysis server
|
||||
$serverPath
|
||||
''');
|
||||
}
|
||||
await server.start(
|
||||
clientId: 'dartfix',
|
||||
clientVersion: 'unspecified',
|
||||
sdkPath: options.sdkPath,
|
||||
serverPath: serverPath,
|
||||
);
|
||||
server.listenToOutput(notificationProcessor: handler.handleEvent);
|
||||
return handler.serverConnected(timeLimit: const Duration(seconds: 30));
|
||||
}
|
||||
|
||||
Future<Progress> startServerAnalysis(
|
||||
Options options, {
|
||||
Progress progress,
|
||||
}) async {
|
||||
logger.trace('');
|
||||
logger.trace('Setup analysis');
|
||||
await server.send(SERVER_REQUEST_SET_SUBSCRIPTIONS,
|
||||
ServerSetSubscriptionsParams([ServerService.STATUS]).toJson());
|
||||
await server.send(
|
||||
ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS,
|
||||
AnalysisSetAnalysisRootsParams(
|
||||
options.targets,
|
||||
const [],
|
||||
).toJson());
|
||||
return progress;
|
||||
}
|
||||
|
||||
List<String> _indentAndWrapDescription(String description) =>
|
||||
description.split('\n').map((line) => ' $line').toList();
|
||||
|
||||
String _relativePath(String filePath) {
|
||||
for (String target in targets) {
|
||||
if (filePath.startsWith(target)) {
|
||||
return filePath.substring(target.length + 1);
|
||||
}
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
void _unsupportedOption(String option) {
|
||||
final version = handler.serverProtocolVersion.toString();
|
||||
logger.stderr('''
|
||||
The --$option option is not supported by analysis server version $version.
|
||||
Please upgrade to a newer version of the Dart SDK to use this option.''');
|
||||
}
|
||||
|
||||
void previewFixes(
|
||||
Logger logger,
|
||||
EditDartfixResult results,
|
||||
) {
|
||||
final Ansi ansi = logger.ansi;
|
||||
|
||||
Map<String, List<DartFixSuggestion>> fileSuggestions = {};
|
||||
for (DartFixSuggestion suggestion in results.suggestions) {
|
||||
String file = suggestion.location.file;
|
||||
fileSuggestions.putIfAbsent(file, () => <DartFixSuggestion>[]);
|
||||
fileSuggestions[file].add(suggestion);
|
||||
}
|
||||
|
||||
// present a diff-like view
|
||||
for (SourceFileEdit sourceFileEdit in results.edits) {
|
||||
String file = sourceFileEdit.file;
|
||||
String relPath = path.relative(file);
|
||||
int count = sourceFileEdit.edits.length;
|
||||
|
||||
logger.stdout('');
|
||||
logger.stdout('${ansi.emphasized(relPath)} '
|
||||
'($count ${pluralize('change', count)}):');
|
||||
|
||||
String source;
|
||||
try {
|
||||
source = File(file).readAsStringSync();
|
||||
} catch (_) {}
|
||||
|
||||
if (source == null) {
|
||||
logger.stdout(' (unable to retrieve source for file)');
|
||||
} else {
|
||||
SourcePrinter sourcePrinter = SourcePrinter(source);
|
||||
|
||||
List<SourceEdit> edits = sortEdits(sourceFileEdit);
|
||||
|
||||
// Apply edits.
|
||||
sourcePrinter.applyEdits(edits);
|
||||
|
||||
// Render the changed lines.
|
||||
sourcePrinter.processChangedLines((lineNumber, lineText) {
|
||||
String prefix = ' line ${lineNumber.toString().padRight(3)} •';
|
||||
logger.stdout('$prefix ${lineText.trim()}');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _Handler
|
||||
with NotificationHandler, ConnectionHandler, AnalysisCompleteHandler {
|
||||
final Driver driver;
|
||||
final Logger logger;
|
||||
final Context context;
|
||||
|
||||
@override
|
||||
final Server server;
|
||||
Version serverProtocolVersion;
|
||||
|
||||
_Handler(this.driver, this.context)
|
||||
: logger = driver.logger,
|
||||
server = driver.server;
|
||||
|
||||
@override
|
||||
bool checkServerProtocolVersion(Version version) {
|
||||
serverProtocolVersion = version;
|
||||
return super.checkServerProtocolVersion(version);
|
||||
}
|
||||
|
||||
@override
|
||||
void onAnalysisErrors(AnalysisErrorsParams params) {
|
||||
List<AnalysisError> errors = params.errors;
|
||||
bool foundAtLeastOneError = false;
|
||||
for (AnalysisError error in errors) {
|
||||
if (shouldShowError(error)) {
|
||||
if (!foundAtLeastOneError) {
|
||||
foundAtLeastOneError = true;
|
||||
logger.stdout('${driver._relativePath(params.file)}:');
|
||||
}
|
||||
Location loc = error.location;
|
||||
logger.stdout(' ${toSentenceFragment(error.message)}'
|
||||
' • ${loc.startLine}:${loc.startColumn}');
|
||||
}
|
||||
}
|
||||
super.onAnalysisErrors(params);
|
||||
// Analysis errors are non-fatal; no need to exit.
|
||||
}
|
||||
|
||||
@override
|
||||
void onFailedToConnect() {
|
||||
logger.stderr('Failed to connect to server');
|
||||
super.onFailedToConnect();
|
||||
// Exiting on connection failure is already handled by [Driver.start].
|
||||
}
|
||||
|
||||
@override
|
||||
void onProtocolNotSupported(Version version) {
|
||||
logger.stderr('Expected protocol version $PROTOCOL_VERSION,'
|
||||
' but found $version');
|
||||
final expectedVersion = Version.parse(PROTOCOL_VERSION);
|
||||
if (version > expectedVersion) {
|
||||
logger.stdout('''
|
||||
This version of dartfix is incompatible with the current Dart SDK.
|
||||
Try installing a newer version of dartfix by running:
|
||||
|
||||
pub global activate dartfix
|
||||
''');
|
||||
} else {
|
||||
logger.stdout('''
|
||||
This version of dartfix is too new to be used with the current Dart SDK. Try
|
||||
upgrading the Dart SDK to a newer version or installing an older version of
|
||||
dartfix using:
|
||||
|
||||
pub global activate dartfix <version>
|
||||
''');
|
||||
}
|
||||
super.onProtocolNotSupported(version);
|
||||
// This is handled by the connection failure case; no need to exit here.
|
||||
}
|
||||
|
||||
@override
|
||||
void onServerError(ServerErrorParams params) {
|
||||
if (params.isFatal) {
|
||||
logger.stderr('Fatal Server Error: ${params.message}');
|
||||
} else {
|
||||
logger.stderr('Server Error: ${params.message}');
|
||||
}
|
||||
if (params.stackTrace != null) {
|
||||
logger.stderr(params.stackTrace);
|
||||
}
|
||||
super.onServerError(params);
|
||||
// Server is stopped by super method, so we can safely exit here.
|
||||
context.exit(16);
|
||||
}
|
||||
}
|
||||
|
||||
class _Listener with ServerListener, BadMessageListener {
|
||||
final Logger logger;
|
||||
final bool verbose;
|
||||
|
||||
_Listener(this.logger) : verbose = logger.isVerbose;
|
||||
|
||||
@override
|
||||
void log(String prefix, String details) {
|
||||
if (verbose) {
|
||||
logger.trace('$prefix $details');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +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 'package:analysis_server_client/protocol.dart';
|
||||
|
||||
import '../util.dart';
|
||||
|
||||
// TODO(devoncarew): This is only referenced from tests.
|
||||
|
||||
/// Perform the indicated source edits to the given source, returning the
|
||||
/// resulting transformed text.
|
||||
String applyEdits(SourceFileEdit sourceFileEdit, String source) {
|
||||
List<SourceEdit> edits = sortEdits(sourceFileEdit);
|
||||
return SourceEdit.applySequence(source, edits);
|
||||
}
|
|
@ -1,88 +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 'package:analysis_server_client/protocol.dart';
|
||||
import 'package:cli_util/cli_logging.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
// TODO(devoncarew): This is only referenced from tests.
|
||||
|
||||
/// Given a Logger and an analysis issue, render the issue to the logger.
|
||||
class IssueRenderer {
|
||||
final Logger logger;
|
||||
final String rootDirectory;
|
||||
|
||||
IssueRenderer(this.logger, this.rootDirectory);
|
||||
|
||||
void render(AnalysisError issue) {
|
||||
// severity • Message ... at foo/bar.dart:6:1 • (error_code)
|
||||
|
||||
final Ansi ansi = logger.ansi;
|
||||
|
||||
logger.stdout(
|
||||
' ${ansi.error(issue.severity.name.toLowerCase())} • '
|
||||
'${ansi.emphasized(_removePeriod(issue.message))} '
|
||||
'at ${path.relative(issue.location.file, from: rootDirectory)}'
|
||||
':${issue.location.startLine}:'
|
||||
'${issue.location.startColumn} '
|
||||
'• (${issue.code})',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
typedef LineProcessor = void Function(int lineNumber, String lineText);
|
||||
|
||||
class SourcePrinter {
|
||||
static final String red = '\u001b[31m';
|
||||
static final String bold = '\u001b[1m';
|
||||
static final String reversed = '\u001b[7m';
|
||||
static final String none = '\u001b[0m';
|
||||
|
||||
String source;
|
||||
|
||||
SourcePrinter(this.source);
|
||||
|
||||
void applyEdits(List<SourceEdit> edits) {
|
||||
for (SourceEdit edit in edits) {
|
||||
if (edit.replacement.isNotEmpty) {
|
||||
// an addition
|
||||
insertText(edit.offset + edit.length, edit.replacement);
|
||||
}
|
||||
|
||||
if (edit.length != 0) {
|
||||
// a removal
|
||||
deleteRange(edit.offset, edit.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deleteRange(int offset, int length) {
|
||||
source = source.substring(0, offset) +
|
||||
red +
|
||||
reversed +
|
||||
source.substring(offset, offset + length) +
|
||||
none +
|
||||
source.substring(offset + length);
|
||||
}
|
||||
|
||||
void insertText(int offset, String text) {
|
||||
text = '$reversed$text$none';
|
||||
source = source.substring(0, offset) + text + source.substring(offset);
|
||||
}
|
||||
|
||||
void processChangedLines(LineProcessor callback) {
|
||||
List<String> lines = source.split('\n');
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
|
||||
if (line.contains(none)) {
|
||||
callback(i + 1, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String _removePeriod(String value) {
|
||||
return value.endsWith('.') ? value.substring(0, value.length - 1) : value;
|
||||
}
|
|
@ -1,96 +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:io';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:args/src/arg_parser.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
// TODO(devoncarew): This class is unused.
|
||||
|
||||
class MigrateOptions {
|
||||
static const applyChangesOption = 'apply-changes';
|
||||
static const debugOption = 'debug';
|
||||
static const ignoreErrorsOption = 'ignore-errors';
|
||||
static const previewPortOption = 'preview-port';
|
||||
static const sdkPathOption = 'sdk-path';
|
||||
static const serverPathOption = 'server-path';
|
||||
static const webPreviewOption = 'web-preview';
|
||||
|
||||
final bool applyChanges;
|
||||
final bool debug;
|
||||
final String directory;
|
||||
final bool ignoreErrors;
|
||||
final int previewPort;
|
||||
final String serverPath;
|
||||
final String sdkPath;
|
||||
final bool webPreview;
|
||||
|
||||
MigrateOptions(ArgResults argResults, this.directory)
|
||||
: applyChanges = argResults[applyChangesOption] as bool,
|
||||
debug = argResults[debugOption] as bool,
|
||||
ignoreErrors = argResults[ignoreErrorsOption] as bool,
|
||||
previewPort =
|
||||
int.tryParse(argResults[previewPortOption] as String) ?? 0,
|
||||
sdkPath = argResults[sdkPathOption] as String,
|
||||
serverPath = argResults[serverPathOption] as String,
|
||||
webPreview = argResults['web-preview'] as bool;
|
||||
|
||||
String get directoryAbsolute => Directory(path.canonicalize(directory)).path;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '[$directory]';
|
||||
}
|
||||
|
||||
static void defineOptions(ArgParser argParser) {
|
||||
argParser.addFlag(
|
||||
applyChangesOption,
|
||||
defaultsTo: false,
|
||||
negatable: false,
|
||||
help: 'Apply the proposed null safety changes to the files on disk.',
|
||||
);
|
||||
argParser.addFlag(
|
||||
debugOption,
|
||||
defaultsTo: false,
|
||||
hide: true,
|
||||
negatable: true,
|
||||
help: 'Show (very verbose) debugging information to stdout during '
|
||||
'migration',
|
||||
);
|
||||
argParser.addFlag(
|
||||
ignoreErrorsOption,
|
||||
defaultsTo: false,
|
||||
negatable: false,
|
||||
help: 'Attempt to perform null safety analysis even if the package has '
|
||||
'analysis errors.',
|
||||
);
|
||||
argParser.addOption(
|
||||
sdkPathOption,
|
||||
hide: true,
|
||||
help: 'Override the SDK path used for migration.',
|
||||
);
|
||||
argParser.addOption(
|
||||
previewPortOption,
|
||||
defaultsTo: '0',
|
||||
help: 'Run the preview server on the specified port. If not specified '
|
||||
'or invalid, dynamically allocate a port.',
|
||||
);
|
||||
argParser.addOption(
|
||||
serverPathOption,
|
||||
hide: true,
|
||||
help: 'Override the analysis server path used for migration.',
|
||||
);
|
||||
argParser.addFlag(
|
||||
webPreviewOption,
|
||||
defaultsTo: true,
|
||||
negatable: true,
|
||||
help: 'Show an interactive preview of the proposed null safety changes '
|
||||
'in a browser window.\n'
|
||||
'With --no-web-preview, the proposed changes are instead printed to '
|
||||
'the console.',
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
// Copyright (c) 2018, 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:args/args.dart';
|
||||
import 'package:cli_util/cli_logging.dart';
|
||||
import 'package:dartfix/src/context.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
// TODO(brianwilkerson) Deprecate 'excludeFix' and replace it with 'exclude-fix'
|
||||
const excludeFixOption = 'excludeFix';
|
||||
const forceOption = 'force';
|
||||
const includeFixOption = 'fix';
|
||||
const overwriteOption = 'overwrite';
|
||||
const pedanticOption = 'pedantic';
|
||||
const previewDirOption = 'preview-dir';
|
||||
const previewPortOption = 'preview-port';
|
||||
const sdkOption = 'sdk';
|
||||
|
||||
const _binaryName = 'dartfix';
|
||||
const _colorOption = 'color';
|
||||
|
||||
// options only supported by server 1.22.2 and greater
|
||||
const _helpOption = 'help';
|
||||
const _serverSnapshot = 'server';
|
||||
|
||||
// options not supported yet by any server
|
||||
const _verboseOption = 'verbose';
|
||||
|
||||
/// Command line options for `dartfix`.
|
||||
class Options {
|
||||
final Context context;
|
||||
Logger logger;
|
||||
|
||||
List<String> targets;
|
||||
final String sdkPath;
|
||||
final String serverSnapshot;
|
||||
|
||||
final bool pedanticFixes;
|
||||
final List<String> includeFixes;
|
||||
final List<String> excludeFixes;
|
||||
|
||||
final bool force;
|
||||
final bool showHelp;
|
||||
bool overwrite;
|
||||
final bool useColor;
|
||||
final bool verbose;
|
||||
|
||||
Options._fromArgs(this.context, ArgResults results)
|
||||
: force = results[forceOption] as bool,
|
||||
includeFixes = (results[includeFixOption] as List ?? []).cast<String>(),
|
||||
excludeFixes = (results[excludeFixOption] as List ?? []).cast<String>(),
|
||||
overwrite = results[overwriteOption] as bool,
|
||||
pedanticFixes = results[pedanticOption] as bool,
|
||||
sdkPath = results[sdkOption] as String ?? _getSdkPath(),
|
||||
serverSnapshot = results[_serverSnapshot] as String,
|
||||
showHelp = results[_helpOption] as bool || results.arguments.isEmpty,
|
||||
targets = results.rest,
|
||||
useColor = results.wasParsed(_colorOption)
|
||||
? results[_colorOption] as bool
|
||||
: null,
|
||||
verbose = results[_verboseOption] as bool;
|
||||
|
||||
String makeAbsoluteAndNormalize(String target) {
|
||||
if (!path.isAbsolute(target)) {
|
||||
target = path.join(context.workingDir, target);
|
||||
}
|
||||
return path.normalize(target);
|
||||
}
|
||||
|
||||
static Options parse(List<String> args, Context context, Logger logger) {
|
||||
final parser = ArgParser(allowTrailingOptions: true)
|
||||
..addSeparator('Choosing fixes to be applied:')
|
||||
..addMultiOption(includeFixOption,
|
||||
help: 'Include a specific fix.', valueHelp: 'name-of-fix')
|
||||
..addMultiOption(excludeFixOption,
|
||||
help: 'Exclude a specific fix.', valueHelp: 'name-of-fix')
|
||||
..addFlag(pedanticOption,
|
||||
help: 'Apply pedantic fixes.', defaultsTo: false, negatable: false)
|
||||
..addSeparator('Modifying files:')
|
||||
..addFlag(overwriteOption,
|
||||
abbr: 'w',
|
||||
help: 'Overwrite files with the changes.',
|
||||
defaultsTo: false,
|
||||
negatable: false)
|
||||
..addFlag(forceOption,
|
||||
abbr: 'f',
|
||||
help: 'Overwrite files even if there are errors.',
|
||||
defaultsTo: false,
|
||||
negatable: false)
|
||||
..addSeparator('Miscellaneous:')
|
||||
..addFlag(_helpOption,
|
||||
abbr: 'h',
|
||||
help: 'Display this help message.',
|
||||
defaultsTo: false,
|
||||
negatable: false)
|
||||
..addOption(sdkOption,
|
||||
help: 'Path to the SDK to analyze against.',
|
||||
valueHelp: 'path',
|
||||
hide: true)
|
||||
..addOption(_serverSnapshot,
|
||||
help: 'Path to the analysis server snapshot file.',
|
||||
valueHelp: 'path',
|
||||
hide: true)
|
||||
..addFlag(_verboseOption,
|
||||
abbr: 'v',
|
||||
help: 'Verbose output.',
|
||||
defaultsTo: false,
|
||||
negatable: false)
|
||||
..addFlag(_colorOption,
|
||||
help: 'Use ansi colors when printing messages.',
|
||||
defaultsTo: Ansi.terminalSupportsAnsi);
|
||||
|
||||
context ??= Context();
|
||||
|
||||
ArgResults results;
|
||||
try {
|
||||
results = parser.parse(args);
|
||||
} on FormatException catch (e) {
|
||||
logger ??= Logger.standard(ansi: Ansi(Ansi.terminalSupportsAnsi));
|
||||
logger.stderr(e.message);
|
||||
_showUsage(parser, logger);
|
||||
context.exit(17);
|
||||
}
|
||||
|
||||
Options options = Options._fromArgs(context, results);
|
||||
|
||||
if (logger == null) {
|
||||
if (options.verbose) {
|
||||
logger = Logger.verbose();
|
||||
} else {
|
||||
logger = Logger.standard(
|
||||
ansi: Ansi(
|
||||
options.useColor ?? Ansi.terminalSupportsAnsi,
|
||||
));
|
||||
}
|
||||
}
|
||||
options.logger = logger;
|
||||
|
||||
// For '--help', we short circuit the logic to validate the sdk and project.
|
||||
if (options.showHelp) {
|
||||
_showUsage(parser, logger, showHelpHint: false);
|
||||
return options;
|
||||
}
|
||||
|
||||
// Validate the Dart SDK location
|
||||
String sdkPath = options.sdkPath;
|
||||
if (sdkPath == null) {
|
||||
logger.stderr('No Dart SDK found.');
|
||||
context.exit(18);
|
||||
}
|
||||
|
||||
if (!context.exists(sdkPath)) {
|
||||
logger.stderr('Invalid Dart SDK path: $sdkPath');
|
||||
context.exit(19);
|
||||
}
|
||||
|
||||
// Check for files and/or directories to analyze.
|
||||
if (options.targets == null || options.targets.isEmpty) {
|
||||
logger.stderr('Expected at least one file or directory to analyze.');
|
||||
context.exit(20);
|
||||
}
|
||||
|
||||
// Normalize and verify paths
|
||||
options.targets =
|
||||
options.targets.map<String>(options.makeAbsoluteAndNormalize).toList();
|
||||
for (String target in options.targets) {
|
||||
if (!context.isDirectory(target)) {
|
||||
if (!context.exists(target)) {
|
||||
logger.stderr('Target does not exist: $target');
|
||||
} else {
|
||||
logger.stderr('Expected directory, but found: $target');
|
||||
}
|
||||
context.exit(21);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.verbose) {
|
||||
logger.trace('Targets:');
|
||||
for (String target in options.targets) {
|
||||
logger.trace(' $target');
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
static String _getSdkPath() {
|
||||
return Platform.environment['DART_SDK'] ??
|
||||
path.dirname(path.dirname(Platform.resolvedExecutable));
|
||||
}
|
||||
|
||||
static void _showUsage(ArgParser parser, Logger logger,
|
||||
{bool showHelpHint = true}) {
|
||||
Function(String message) out = showHelpHint ? logger.stderr : logger.stdout;
|
||||
// show help on stdout when showHelp is true and showHelpHint is false
|
||||
out('''
|
||||
Usage: $_binaryName [options...] <directory paths>
|
||||
''');
|
||||
out(parser.usage);
|
||||
out(showHelpHint
|
||||
? '''
|
||||
|
||||
Use --$_helpOption to display the fixes that can be specified using either
|
||||
--$includeFixOption or --$excludeFixOption.'''
|
||||
: '');
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright (c) 2018, 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' show File, Platform;
|
||||
|
||||
import 'package:analysis_server_client/protocol.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
int compareSuggestions(DartFixSuggestion s1, DartFixSuggestion s2) {
|
||||
int result = s1.description.compareTo(s2.description);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return (s2.location?.offset ?? 0) - (s1.location?.offset ?? 0);
|
||||
}
|
||||
|
||||
int compareFixes(DartFix s1, DartFix s2) {
|
||||
return s1.name.compareTo(s2.name);
|
||||
}
|
||||
|
||||
/// Return the analysis_server executable by proceeding upward until finding the
|
||||
/// Dart SDK repository root, then returning the analysis_server executable
|
||||
/// within the repository.
|
||||
///
|
||||
/// Return `null` if it cannot be found.
|
||||
String findServerPath() {
|
||||
String pathname = Platform.script.toFilePath();
|
||||
while (true) {
|
||||
String parent = path.dirname(pathname);
|
||||
if (parent.length >= pathname.length) {
|
||||
return null;
|
||||
}
|
||||
String serverPath =
|
||||
path.join(parent, 'pkg', 'analysis_server', 'bin', 'server.dart');
|
||||
if (File(serverPath).existsSync()) {
|
||||
return serverPath;
|
||||
}
|
||||
pathname = parent;
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldShowError(AnalysisError error) {
|
||||
// Only show diagnostics that will affect the fixes.
|
||||
return error.type.name != 'HINT' &&
|
||||
error.type.name != 'LINT' &&
|
||||
error.type.name != 'TODO' &&
|
||||
// TODO(danrubel): Rather than checking the error.code with
|
||||
// specific strings, add something to the error indicating that
|
||||
// it will be automatically fixed by edit.dartfix.
|
||||
error.code != 'wrong_number_of_type_arguments_constructor';
|
||||
}
|
||||
|
||||
String toSentenceFragment(String message) {
|
||||
return message.endsWith('.')
|
||||
? message.substring(0, message.length - 1)
|
||||
: message;
|
||||
}
|
||||
|
||||
String pluralize(String word, int count) => count == 1 ? word : '${word}s';
|
||||
|
||||
List<SourceEdit> sortEdits(SourceFileEdit sourceFileEdit) {
|
||||
// Sort edits in reverse offset order.
|
||||
List<SourceEdit> edits = sourceFileEdit.edits.toList();
|
||||
edits.sort((a, b) {
|
||||
return b.offset - a.offset;
|
||||
});
|
||||
return edits;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
name: dartfix
|
||||
version: 0.1.8
|
||||
description:
|
||||
A tool for migrating Dart source to newer versions of the Dart SDK
|
||||
and fixing common issues.
|
||||
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dartfix
|
||||
environment:
|
||||
sdk: '>=2.8.0 <3.0.0'
|
||||
|
||||
# Add the bin/dartfix.dart script to the scripts pub installs.
|
||||
executables:
|
||||
dartfix:
|
||||
|
||||
dependencies:
|
||||
# Pin to an exact version of analysis_server_client because the edit.dartfix
|
||||
# protocol is experimental and will continue to evolve.
|
||||
analysis_server_client: '>=1.1.3 <1.1.4'
|
||||
args: ^1.4.0
|
||||
cli_util: ^0.2.0
|
||||
path: ^1.7.0
|
||||
pub_semver: ^1.4.4
|
||||
|
||||
dev_dependencies:
|
||||
analyzer: ^0.40.0
|
||||
pedantic: ^1.8.0
|
||||
test: ^1.14.2
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright (c) 2019, 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:test/test.dart';
|
||||
|
||||
import 'test_context.dart';
|
||||
|
||||
void main() {
|
||||
test('run original example', () async {
|
||||
File exampleFile = findFile('pkg/dartfix/example/example.dart');
|
||||
|
||||
print('--- launching original example');
|
||||
final futureResult1 =
|
||||
Process.run(Platform.resolvedExecutable, [exampleFile.path]);
|
||||
|
||||
print('--- waiting for original example');
|
||||
final result = await futureResult1;
|
||||
|
||||
print('--- original example output');
|
||||
var text = result.stdout as String;
|
||||
print(text);
|
||||
|
||||
expect(text.trim(), 'myDouble = 4.0');
|
||||
});
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright (c) 2019, 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:dartfix/src/driver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'test_context.dart';
|
||||
|
||||
void main() {
|
||||
File exampleFile;
|
||||
Directory exampleDir;
|
||||
|
||||
test('exclude fix', () async {
|
||||
exampleFile = findFile('pkg/dartfix/example/example.dart');
|
||||
exampleDir = exampleFile.parent;
|
||||
|
||||
final driver = Driver();
|
||||
final testContext = TestContext();
|
||||
final testLogger = TestLogger(debug: _debug);
|
||||
String exampleSource = await exampleFile.readAsString();
|
||||
|
||||
try {
|
||||
await driver.start([
|
||||
if (_debug) '-v',
|
||||
'--fix',
|
||||
'convert_class_to_mixin',
|
||||
'--excludeFix',
|
||||
'convert_class_to_mixin',
|
||||
exampleDir.path,
|
||||
], testContext: testContext, testLogger: testLogger);
|
||||
} finally {
|
||||
if (_debug) {
|
||||
print(testLogger.stderrBuffer.toString());
|
||||
print(testLogger.stdoutBuffer.toString());
|
||||
print('--- original example');
|
||||
print(exampleSource);
|
||||
}
|
||||
}
|
||||
|
||||
final suggestions = driver.result.suggestions;
|
||||
expect(suggestions, hasLength(0));
|
||||
}, timeout: const Timeout(Duration(minutes: 3)));
|
||||
}
|
||||
|
||||
const _debug = true;
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright (c) 2019, 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:dartfix/src/driver.dart';
|
||||
import 'package:dartfix/src/options.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'test_context.dart';
|
||||
|
||||
void main() {
|
||||
test('help explicit', () async {
|
||||
final driver = Driver();
|
||||
final testContext = TestContext();
|
||||
final testLogger = TestLogger();
|
||||
try {
|
||||
await driver.start(
|
||||
['--help'], // display help and list fixes
|
||||
testContext: testContext,
|
||||
testLogger: testLogger,
|
||||
);
|
||||
fail('expected exception');
|
||||
} on TestExit catch (e) {
|
||||
expect(e.code, 0);
|
||||
}
|
||||
final errText = testLogger.stderrBuffer.toString();
|
||||
final outText = testLogger.stdoutBuffer.toString();
|
||||
expect(errText, isEmpty);
|
||||
expect(outText, contains('--$excludeFixOption'));
|
||||
expect(outText, isNot(contains('Use --help to display the fixes')));
|
||||
});
|
||||
|
||||
test('help implicit', () async {
|
||||
final driver = Driver();
|
||||
final testContext = TestContext();
|
||||
final testLogger = TestLogger();
|
||||
try {
|
||||
await driver.start(
|
||||
[], // no options or arguments should display help and list fixes
|
||||
testContext: testContext,
|
||||
testLogger: testLogger,
|
||||
);
|
||||
fail('expected exception');
|
||||
} on TestExit catch (e) {
|
||||
expect(e.code, 0);
|
||||
}
|
||||
final errText = testLogger.stderrBuffer.toString();
|
||||
final outText = testLogger.stdoutBuffer.toString();
|
||||
print(errText);
|
||||
print(outText);
|
||||
expect(errText, isEmpty);
|
||||
expect(outText, contains('--$excludeFixOption'));
|
||||
expect(outText, isNot(contains('Use --help to display the fixes')));
|
||||
});
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright (c) 2019, 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:dartfix/src/driver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'test_context.dart';
|
||||
|
||||
void main() {
|
||||
File exampleFile;
|
||||
Directory exampleDir;
|
||||
|
||||
test('include fix', () async {
|
||||
exampleFile = findFile('pkg/dartfix/example/example.dart');
|
||||
exampleDir = exampleFile.parent;
|
||||
|
||||
final driver = Driver();
|
||||
final testContext = TestContext();
|
||||
final testLogger = TestLogger(debug: _debug);
|
||||
String exampleSource = await exampleFile.readAsString();
|
||||
|
||||
try {
|
||||
await driver.start([
|
||||
if (_debug) '-v',
|
||||
'--fix',
|
||||
'prefer_int_literals',
|
||||
exampleDir.path,
|
||||
], testContext: testContext, testLogger: testLogger);
|
||||
} finally {
|
||||
if (_debug) {
|
||||
print(testLogger.stderrBuffer.toString());
|
||||
print(testLogger.stdoutBuffer.toString());
|
||||
print('--- original example');
|
||||
print(exampleSource);
|
||||
}
|
||||
}
|
||||
|
||||
final suggestions = driver.result.suggestions;
|
||||
expect(suggestions, hasLength(1));
|
||||
expectHasSuggestion(suggestions, 'Convert to an int literal');
|
||||
}, timeout: const Timeout(Duration(minutes: 3)));
|
||||
}
|
||||
|
||||
const _debug = true;
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright (c) 2019, 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 'driver_test.dart' show defineDriverTests;
|
||||
|
||||
void main() {
|
||||
defineDriverTests(
|
||||
name: 'pedantic',
|
||||
options: ['--pedantic'],
|
||||
expectedSuggestions: ["Replace with 'isEmpty'"],
|
||||
);
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright (c) 2019, 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 'driver_test.dart' show defineDriverTests;
|
||||
|
||||
void main() {
|
||||
defineDriverTests(
|
||||
name: 'prefer_is_empty',
|
||||
options: ['--fix', 'prefer_is_empty'],
|
||||
expectedSuggestions: ["Replace with 'isEmpty'"],
|
||||
);
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
// Copyright (c) 2018, 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:analysis_server_client/protocol.dart';
|
||||
import 'package:dartfix/src/driver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'test_context.dart';
|
||||
|
||||
void main() {
|
||||
defineDriverTests(
|
||||
name: 'default',
|
||||
options: [
|
||||
'--fix',
|
||||
'prefer_int_literals',
|
||||
'--fix',
|
||||
'convert_class_to_mixin'
|
||||
],
|
||||
expectedSuggestions: [
|
||||
'Convert MyMixin to a mixin',
|
||||
'Convert to an int literal',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void defineDriverTests({
|
||||
String name,
|
||||
List<String> options,
|
||||
List<String> expectedSuggestions,
|
||||
bool debug = false,
|
||||
bool updateExample = false,
|
||||
}) {
|
||||
var fixFileName = 'example_$name.dart';
|
||||
|
||||
File exampleFile;
|
||||
File exampleFixedFile;
|
||||
Directory exampleDir;
|
||||
|
||||
setUp(() {
|
||||
exampleFile = findFile('pkg/dartfix/example/example.dart');
|
||||
exampleFixedFile = findFile('pkg/dartfix/fixed/$fixFileName');
|
||||
exampleDir = exampleFile.parent;
|
||||
});
|
||||
|
||||
test('fix example - $name', () async {
|
||||
final driver = Driver();
|
||||
final testContext = TestContext();
|
||||
final testLogger = TestLogger(debug: debug);
|
||||
String exampleSource = await exampleFile.readAsString();
|
||||
|
||||
await driver.start([if (debug) '-v', ...options, exampleDir.path],
|
||||
testContext: testContext, testLogger: testLogger);
|
||||
if (debug) {
|
||||
print(testLogger.stderrBuffer.toString());
|
||||
print(testLogger.stdoutBuffer.toString());
|
||||
print('--- original example');
|
||||
print(exampleSource);
|
||||
}
|
||||
|
||||
expect(driver.result.edits, hasLength(1));
|
||||
for (SourceEdit edit in driver.result.edits[0].edits) {
|
||||
exampleSource = edit.apply(exampleSource);
|
||||
}
|
||||
if (debug) {
|
||||
print('--- fixed example');
|
||||
print(exampleSource);
|
||||
}
|
||||
|
||||
final suggestions = driver.result.suggestions;
|
||||
for (var expectedSuggestion in expectedSuggestions) {
|
||||
expectHasSuggestion(suggestions, expectedSuggestion);
|
||||
}
|
||||
expect(suggestions, hasLength(expectedSuggestions.length));
|
||||
|
||||
exampleSource = replaceLeadingComment(exampleSource);
|
||||
if (updateExample) {
|
||||
await exampleFixedFile.writeAsString(exampleSource);
|
||||
} else {
|
||||
final expectedSource = await exampleFixedFile.readAsString();
|
||||
expect(exampleSource, expectedSource);
|
||||
}
|
||||
}, timeout: const Timeout(Duration(minutes: 3)));
|
||||
|
||||
test('run example - $name', () async {
|
||||
if (debug) print('--- launching original example');
|
||||
final futureResult1 =
|
||||
Process.run(Platform.resolvedExecutable, [exampleFile.path]);
|
||||
|
||||
if (debug) print('--- launching fixed example');
|
||||
final futureResult2 =
|
||||
Process.run(Platform.resolvedExecutable, [exampleFixedFile.path]);
|
||||
|
||||
if (debug) print('--- waiting for original example');
|
||||
final result1 = await futureResult1;
|
||||
|
||||
if (debug) print('--- waiting for fixed example');
|
||||
final result2 = await futureResult2;
|
||||
|
||||
final stdout1 = result1.stdout;
|
||||
final stdout2 = result2.stdout;
|
||||
if (debug) {
|
||||
print('--- original example output');
|
||||
print(stdout1);
|
||||
print('--- fixed example output');
|
||||
print(stdout2);
|
||||
}
|
||||
expect(stdout1, stdout2);
|
||||
});
|
||||
}
|
||||
|
||||
String replaceLeadingComment(String source) => source.replaceAll(
|
||||
'''
|
||||
// This file contains code that is modified by running dartfix.
|
||||
// After running dartfix, this content matches a file in the "fixed" directory.
|
||||
'''
|
||||
.trim(),
|
||||
'''
|
||||
// This file contains code that has been modified by running dartfix.
|
||||
// See example.dart for the original unmodified code.
|
||||
'''
|
||||
.trim());
|
|
@ -1,200 +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:io';
|
||||
|
||||
import 'package:analysis_server_client/protocol.dart';
|
||||
import 'package:cli_util/cli_logging.dart';
|
||||
import 'package:dartfix/src/migrate/apply.dart';
|
||||
import 'package:dartfix/src/migrate/display.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
defineMigrateTests();
|
||||
}
|
||||
|
||||
void defineMigrateTests() {
|
||||
group('issue render', defineIssueRenderTests);
|
||||
group('SourcePrinter', defineSourcePrinterTests);
|
||||
group('applyEdits', defineApplyEditsTests);
|
||||
}
|
||||
|
||||
void defineIssueRenderTests() {
|
||||
IssueRenderer renderer;
|
||||
TestLogger logger;
|
||||
|
||||
setUp(() {
|
||||
logger = TestLogger();
|
||||
renderer = IssueRenderer(logger, '.');
|
||||
});
|
||||
|
||||
test('issue1', () {
|
||||
AnalysisError issue = AnalysisError(
|
||||
AnalysisErrorSeverity.ERROR,
|
||||
AnalysisErrorType.COMPILE_TIME_ERROR,
|
||||
Location('foo/bar/baz.dart', 1, 2, 3, 4),
|
||||
'My message.',
|
||||
'my_error_code',
|
||||
);
|
||||
|
||||
renderer.render(issue);
|
||||
|
||||
expect(
|
||||
logger.stdoutText.trim(),
|
||||
contains(platformPath(
|
||||
'error • My message at foo/bar/baz.dart:3:4 • (my_error_code)')),
|
||||
);
|
||||
expect(logger.stderrText, isEmpty);
|
||||
});
|
||||
|
||||
test('issue2', () {
|
||||
AnalysisError issue = AnalysisError(
|
||||
AnalysisErrorSeverity.INFO,
|
||||
AnalysisErrorType.TODO,
|
||||
Location('foo/bar/qux.dart', 1, 2, 3, 4),
|
||||
'todo: My message.',
|
||||
'todo',
|
||||
);
|
||||
|
||||
renderer.render(issue);
|
||||
|
||||
expect(
|
||||
logger.stdoutText,
|
||||
contains(platformPath(
|
||||
'info • todo: My message at foo/bar/qux.dart:3:4 • (todo)')));
|
||||
|
||||
expect(logger.stderrText, isEmpty);
|
||||
});
|
||||
}
|
||||
|
||||
void defineSourcePrinterTests() {
|
||||
SourcePrinter printer;
|
||||
|
||||
setUp(() {
|
||||
printer = SourcePrinter('''
|
||||
void main() {
|
||||
Cat one = Cat('Tabby');
|
||||
print(one);
|
||||
}
|
||||
|
||||
class Cat {
|
||||
final String name;
|
||||
String color;
|
||||
|
||||
Cat(this.name);
|
||||
|
||||
String toString() {
|
||||
return name?.toString() + ' is ' + color.toString();
|
||||
}
|
||||
}
|
||||
''');
|
||||
});
|
||||
|
||||
test('add and remove', () {
|
||||
printer.insertText(192, '?');
|
||||
printer.deleteRange(164, 1);
|
||||
printer.insertText(98, '?');
|
||||
|
||||
StringBuffer buf = StringBuffer();
|
||||
printer.processChangedLines((lineNumber, lineText) {
|
||||
buf.writeln('$lineNumber ${lineText.trim()}');
|
||||
});
|
||||
|
||||
expect(buf.toString().trim(), '''
|
||||
8 String\x1B[7m?\x1B[0m color;
|
||||
13 return name?\x1B[31m\x1B[7m.\x1B[0mtoString() + \' is \' + color\x1B[7m?\x1B[0m.toString();''');
|
||||
});
|
||||
}
|
||||
|
||||
void defineApplyEditsTests() {
|
||||
test('insert', () {
|
||||
String source = 'one two\nthree four';
|
||||
SourceFileEdit edit = SourceFileEdit('foo.dart', 0, edits: [
|
||||
SourceEdit(0, 0, 'five '),
|
||||
]);
|
||||
|
||||
String result = applyEdits(edit, source);
|
||||
expect(result, 'five one two\nthree four');
|
||||
});
|
||||
|
||||
test('delete', () {
|
||||
String source = 'one two\nthree four';
|
||||
SourceFileEdit edit = SourceFileEdit('foo.dart', 0, edits: [
|
||||
SourceEdit(0, 4, ''),
|
||||
SourceEdit(8, 6, ''),
|
||||
]);
|
||||
|
||||
String result = applyEdits(edit, source);
|
||||
expect(result, 'two\nfour');
|
||||
});
|
||||
|
||||
test('insert and delete', () {
|
||||
String source = 'one two\nthree four';
|
||||
SourceFileEdit edit = SourceFileEdit('foo.dart', 0, edits: [
|
||||
SourceEdit(13, 5, ''),
|
||||
SourceEdit(8, 0, 'six '),
|
||||
SourceEdit(7, 1, ' '),
|
||||
]);
|
||||
|
||||
String result = applyEdits(edit, source);
|
||||
expect(result, 'one two six three');
|
||||
});
|
||||
}
|
||||
|
||||
class TestLogger implements Logger {
|
||||
final bool debug;
|
||||
|
||||
@override
|
||||
final Ansi ansi;
|
||||
final stdoutBuffer = StringBuffer();
|
||||
final stderrBuffer = StringBuffer();
|
||||
|
||||
TestLogger({this.debug = false}) : ansi = Ansi(false);
|
||||
|
||||
@override
|
||||
void flush() {}
|
||||
|
||||
@override
|
||||
bool get isVerbose => debug;
|
||||
|
||||
@override
|
||||
Progress progress(String message) {
|
||||
return SimpleProgress(this, message);
|
||||
}
|
||||
|
||||
@override
|
||||
void stdout(String message) {
|
||||
stdoutBuffer.writeln(message);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(String message) {
|
||||
stdoutBuffer.write(message);
|
||||
}
|
||||
|
||||
@override
|
||||
void writeCharCode(int charCode) {
|
||||
stdoutBuffer.writeCharCode(charCode);
|
||||
}
|
||||
|
||||
@override
|
||||
void stderr(String message) {
|
||||
stderrBuffer.writeln(message);
|
||||
}
|
||||
|
||||
@override
|
||||
void trace(String message) {
|
||||
if (debug) {
|
||||
stdoutBuffer.writeln(message);
|
||||
}
|
||||
}
|
||||
|
||||
String get stdoutText => stdoutBuffer.toString();
|
||||
|
||||
String get stderrText => stderrBuffer.toString();
|
||||
}
|
||||
|
||||
String platformPath(String path) {
|
||||
return path.replaceAll('/', Platform.pathSeparator);
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
// Copyright (c) 2018, 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:dartfix/src/options.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'test_context.dart';
|
||||
|
||||
void main() {
|
||||
TestContext context;
|
||||
TestLogger logger;
|
||||
|
||||
setUp(() {
|
||||
context = TestContext();
|
||||
logger = TestLogger();
|
||||
});
|
||||
|
||||
String p(String filePath) => context.convertPath(filePath);
|
||||
|
||||
Options parse(
|
||||
List<String> args, {
|
||||
String errorOut,
|
||||
int exitCode,
|
||||
bool force = false,
|
||||
List<String> includeFixes = const <String>[],
|
||||
List<String> excludeFixes = const <String>[],
|
||||
bool showHelp = false,
|
||||
String normalOut,
|
||||
bool dependencies = false,
|
||||
bool pedanticFixes = false,
|
||||
bool requiredFixes = false,
|
||||
bool overwrite = false,
|
||||
String serverSnapshot,
|
||||
List<String> targetSuffixes,
|
||||
bool verbose = false,
|
||||
}) {
|
||||
Options options;
|
||||
int actualExitCode;
|
||||
try {
|
||||
options = Options.parse(args, context, logger);
|
||||
} on TestExit catch (e) {
|
||||
actualExitCode = e.code;
|
||||
}
|
||||
expect(logger.stderrBuffer.toString(),
|
||||
errorOut != null ? contains(errorOut) : isEmpty);
|
||||
expect(logger.stdoutBuffer.toString(),
|
||||
normalOut != null ? contains(normalOut) : isEmpty);
|
||||
if (exitCode != null) {
|
||||
expect(actualExitCode, exitCode, reason: 'exit code');
|
||||
return null;
|
||||
} else {
|
||||
expect(actualExitCode, isNull, reason: 'exit code');
|
||||
}
|
||||
expect(options.force, force);
|
||||
expect(options.pedanticFixes, pedanticFixes);
|
||||
expect(options.overwrite, overwrite);
|
||||
expect(options.serverSnapshot, serverSnapshot);
|
||||
expect(options.showHelp, showHelp);
|
||||
expect(options.includeFixes, includeFixes);
|
||||
expect(options.excludeFixes, excludeFixes);
|
||||
expect(options.verbose, verbose);
|
||||
expect(path.isAbsolute(options.sdkPath), isTrue, reason: options.sdkPath);
|
||||
for (String target in options.targets) {
|
||||
expect(target, isNotNull);
|
||||
expect(path.isAbsolute(target), isTrue, reason: '$target');
|
||||
}
|
||||
if (targetSuffixes != null) {
|
||||
for (String suffix in targetSuffixes) {
|
||||
expectContains(options.targets, suffix);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
test('exclude fix', () {
|
||||
parse(['--excludeFix', 'c', '--excludeFix', 'd', 'foo'],
|
||||
excludeFixes: ['c', 'd'], targetSuffixes: ['foo']);
|
||||
});
|
||||
|
||||
test('force', () {
|
||||
parse(['--force', 'foo'], force: true, targetSuffixes: ['foo']);
|
||||
});
|
||||
|
||||
test('help explicit', () {
|
||||
parse(['--help'], normalOut: 'Display this help message', showHelp: true);
|
||||
});
|
||||
|
||||
test('help implicit', () {
|
||||
parse([], normalOut: 'Display this help message', showHelp: true);
|
||||
});
|
||||
|
||||
test('include fix', () {
|
||||
parse(['--fix', 'a', '--fix', 'b', 'foo'],
|
||||
includeFixes: ['a', 'b'], targetSuffixes: ['foo']);
|
||||
});
|
||||
|
||||
test('invalid option', () {
|
||||
parse(['--foo'],
|
||||
errorOut: 'Could not find an option named "foo"', exitCode: 17);
|
||||
});
|
||||
|
||||
test('invalid option no logger', () {
|
||||
try {
|
||||
Options.parse(['--foo'], context, null);
|
||||
fail('Expected exception');
|
||||
} on TestExit catch (e) {
|
||||
expect(e.code, 17, reason: 'exit code');
|
||||
}
|
||||
});
|
||||
|
||||
test('invalid target', () {
|
||||
parse(['foo.dart'],
|
||||
errorOut: 'Expected directory, but found', exitCode: 21);
|
||||
});
|
||||
|
||||
test('overwrite', () {
|
||||
parse(['--overwrite', 'foo'], overwrite: true, targetSuffixes: ['foo']);
|
||||
});
|
||||
|
||||
test('pedantic fixes', () {
|
||||
parse(['--pedantic', 'foo'], pedanticFixes: true);
|
||||
});
|
||||
|
||||
test('server snapshot', () {
|
||||
parse(['--server', 'some/path', 'foo'], serverSnapshot: 'some/path');
|
||||
});
|
||||
|
||||
test('simple', () {
|
||||
parse(['foo'], targetSuffixes: ['foo']);
|
||||
});
|
||||
|
||||
test('two targets', () {
|
||||
parse([p('one/foo'), p('two/bar')],
|
||||
targetSuffixes: [p('one/foo'), p('two/bar')]);
|
||||
});
|
||||
|
||||
test('verbose', () {
|
||||
parse(['--verbose', 'foo'], verbose: true);
|
||||
});
|
||||
}
|
||||
|
||||
void expectContains(Iterable<String> collection, String suffix) {
|
||||
for (String elem in collection) {
|
||||
if (elem.endsWith(suffix)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail('Expected one of $collection\n to end with "$suffix"');
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
// Copyright (c) 2018, 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:analysis_server_client/protocol.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:cli_util/cli_logging.dart';
|
||||
import 'package:dartfix/src/context.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
class TestContext with ResourceProviderMixin implements Context {
|
||||
@override
|
||||
String get workingDir => convertPath('/usr/some/non/existing/directory');
|
||||
|
||||
@override
|
||||
bool exists(String filePath) => true;
|
||||
|
||||
@override
|
||||
void exit(int code) {
|
||||
throw TestExit(code);
|
||||
}
|
||||
|
||||
@override
|
||||
bool isDirectory(String filePath) => !filePath.endsWith('.dart');
|
||||
}
|
||||
|
||||
class TestExit {
|
||||
final int code;
|
||||
|
||||
TestExit(this.code);
|
||||
|
||||
@override
|
||||
String toString() => 'TestExit($code)';
|
||||
}
|
||||
|
||||
class TestLogger implements Logger {
|
||||
final bool debug;
|
||||
|
||||
@override
|
||||
final Ansi ansi;
|
||||
final stdoutBuffer = StringBuffer();
|
||||
final stderrBuffer = StringBuffer();
|
||||
|
||||
TestLogger({this.debug = false}) : ansi = Ansi(false);
|
||||
|
||||
@override
|
||||
void flush() {}
|
||||
|
||||
@override
|
||||
bool get isVerbose => debug;
|
||||
|
||||
@override
|
||||
Progress progress(String message) {
|
||||
return SimpleProgress(this, message);
|
||||
}
|
||||
|
||||
@override
|
||||
void stderr(String message) {
|
||||
stderrBuffer.writeln(message);
|
||||
}
|
||||
|
||||
@override
|
||||
void stdout(String message) {
|
||||
stdoutBuffer.writeln(message);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(String message) {
|
||||
stdoutBuffer.write(message);
|
||||
}
|
||||
|
||||
@override
|
||||
void writeCharCode(int charCode) {
|
||||
stdoutBuffer.writeCharCode(charCode);
|
||||
}
|
||||
|
||||
@override
|
||||
void trace(String message) {
|
||||
if (debug) {
|
||||
stdoutBuffer.writeln(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void expectHasSuggestion(
|
||||
List<DartFixSuggestion> suggestions, String expectedText) {
|
||||
for (DartFixSuggestion suggestion in suggestions) {
|
||||
if (suggestion.description.contains(expectedText)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail('Failed to find suggestion containing: $expectedText\n'
|
||||
'in ${suggestions.map((s) => s.description).toList()}');
|
||||
}
|
||||
|
||||
void expectDoesNotHaveSuggestion(
|
||||
List<DartFixSuggestion> suggestions, String expectedText) {
|
||||
for (DartFixSuggestion suggestion in suggestions) {
|
||||
if (suggestion.description.contains(expectedText)) {
|
||||
fail('Did not expect to find suggestion containing: $expectedText');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File findFile(String relPath) {
|
||||
Directory dir = Directory.current;
|
||||
while (true) {
|
||||
final file = File.fromUri(dir.uri.resolve(relPath));
|
||||
if (file.existsSync()) {
|
||||
return file;
|
||||
}
|
||||
final parent = dir.parent;
|
||||
if (parent.path == dir.path) {
|
||||
fail('Failed to find $relPath');
|
||||
}
|
||||
dir = parent;
|
||||
}
|
||||
}
|
||||
|
||||
String findValue(File pubspec, String key) {
|
||||
List<String> lines = pubspec.readAsLinesSync();
|
||||
for (String line in lines) {
|
||||
if (line.trim().startsWith('$key:')) {
|
||||
return line.split(':')[1].trim();
|
||||
}
|
||||
}
|
||||
fail('Failed to find $key in ${pubspec.path}');
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) 2018, 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:test/test.dart';
|
||||
|
||||
import 'src/driver_example_test.dart' as driver_example;
|
||||
import 'src/driver_exclude_test.dart' as driver_exclude;
|
||||
import 'src/driver_help_test.dart' as driver_help;
|
||||
import 'src/driver_include_test.dart' as driver_include;
|
||||
import 'src/driver_pedantic_test.dart' as driver_pedantic;
|
||||
import 'src/driver_prefer_is_empty_test.dart' as driver_prefer_is_empty;
|
||||
import 'src/driver_test.dart' as driver;
|
||||
import 'src/migrate_command_test.dart' as migrate_command_test;
|
||||
import 'src/options_test.dart' as options_test;
|
||||
|
||||
void main() {
|
||||
group('driver', driver_example.main);
|
||||
group('driver', driver_exclude.main);
|
||||
group('driver', driver_help.main);
|
||||
group('driver', driver_include.main);
|
||||
group('driver', driver_pedantic.main);
|
||||
group('driver', driver_prefer_is_empty.main);
|
||||
group('driver', driver.main);
|
||||
group('migrate', migrate_command_test.main);
|
||||
group('options', options_test.main);
|
||||
}
|
Loading…
Reference in a new issue