diff --git a/.github/workflows/dart_ci.yaml b/.github/workflows/dart_ci.yaml index 18eb1a2..6ee8e98 100644 --- a/.github/workflows/dart_ci.yaml +++ b/.github/workflows/dart_ci.yaml @@ -12,11 +12,18 @@ jobs: # Runs analysis, formatting, and dependency validation against the dart source. checks: uses: Workiva/gha-dart-oss/.github/workflows/checks.yaml@v0.1.14 + with: + sdk: 3.13.4 + format-check: false # Generates an SBOM and uploads it via anchore/sbom-action. build: uses: Workiva/gha-dart-oss/.github/workflows/build.yaml@v0.1.14 + with: + sdk: 3.13.4 # Runs unit tests in dev mode. unit-tests: uses: Workiva/gha-dart-oss/.github/workflows/test-unit.yaml@v0.1.14 + with: + sdk: 3.13.4 \ No newline at end of file diff --git a/.github/workflows/dart_publish.yaml b/.github/workflows/dart_publish.yaml index 1f899d0..d202126 100644 --- a/.github/workflows/dart_publish.yaml +++ b/.github/workflows/dart_publish.yaml @@ -14,3 +14,5 @@ jobs: # Generates and uploads an SBOM, then publishes to pub.dev. publish: uses: Workiva/gha-dart-oss/.github/workflows/publish.yaml@v0.1.14 + with: + sdk: 3.13.4 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e64385..823816b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## Unreleased + +- **Breaking:** Require analyzer `^14.0.0` and Dart SDK `^3.13.0`. + ## [1.3.0](https://github.com/Workiva/dart_codemod/compare/1.2.0...1.3.0) - Allow up to analyzer 10 diff --git a/README.md b/README.md index a463ebc..4513999 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,16 @@ the AST. Inspired by and based on [Facebook's `codemod` library][facebook-codemod]. +## Requirements + +- Dart SDK `^3.13.0` +- [`package:analyzer`][analyzer] `^14.0.0` + +Suggestors that use the analyzer's AST or element APIs should be written +against analyzer 14. Notably, library names are represented by `DottedName` +nodes (use `DottedName.tokens`), `LibraryIdentifier` no longer exists, and +parse/analysis diagnostics expose `diagnosticCode` instead of `errorCode`. + ## Demo ![demo](images/demo.gif) @@ -21,10 +31,10 @@ apply code modifications and refactors via an interactive CLI. To that end, the following function is provided: ```dart -Future runInteractiveCodemod(Iterable files, Suggestor suggestor); +Future runInteractiveCodemod(Iterable filePaths, Suggestor suggestor); ``` -Calling this will tell codemod run the `suggestor` on each file in `files`. For +Calling this will tell codemod run the `suggestor` on each file in `filePaths`. For each file, the suggestor will return a stream of patches that should be suggested to the user. As patches are suggested and accepted by the user, codemod handles applying them to the files and writing the result to disk. @@ -122,7 +132,8 @@ Consider the following suggestor that removes all deprecated declarations (i.e. classes, constructors, variables, methods, etc.): ```dart -import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/visitor.dart'; import 'package:codemod/codemod.dart'; class DeprecatedRemover extends GeneralizingAstVisitor @@ -326,8 +337,7 @@ Let's use the `DeprecatedRemover` suggestor example from above to demonstrate testing: ```dart -import 'package:codemod/codemod.dart'; -import 'package:source_span/source_span.dart'; +import 'package:codemod/test.dart'; import 'package:test/test.dart'; void main() { @@ -365,8 +375,7 @@ that has access to the whole package and its dependencies. You can then add source file(s) and use the wrapping `FileContext`s to test suggestors. ```dart -import 'package:codemod/codemod.dart'; -import 'package:source_span/source_span.dart'; +import 'package:codemod/test.dart'; import 'package:test/test.dart'; void main() { diff --git a/lib/src/ast_visiting_suggestor.dart b/lib/src/ast_visiting_suggestor.dart index 78ce816..06f06a6 100644 --- a/lib/src/ast_visiting_suggestor.dart +++ b/lib/src/ast_visiting_suggestor.dart @@ -28,7 +28,8 @@ final _log = Logger('AstVisitingSuggestor'); /// The easiest way to understand this pattern is to see an example. Consider /// the following suggestor that aims to remove all deprecated declarations: /// -/// import 'package:analyzer/analyzer.dart'; +/// import 'package:analyzer/dart/ast/ast.dart'; +/// import 'package:analyzer/dart/ast/visitor.dart'; /// import 'package:codemod/codemod.dart'; /// /// class DeprecatedRemover extends GeneralizingAstVisitor diff --git a/lib/src/file_context.dart b/lib/src/file_context.dart index b84b334..9bb4149 100644 --- a/lib/src/file_context.dart +++ b/lib/src/file_context.dart @@ -79,8 +79,8 @@ class FileContext { var buffer = StringBuffer(); for (var error in result.errors) { var location = result.lineInfo.getLocation(error.offset); - // ignore: deprecated_member_use - buffer.writeln(' ${error.errorCode.name}: ${error.message} - ' + buffer.writeln( + ' ${error.diagnosticCode.lowerCaseName}: ${error.message} - ' '${location.lineNumber}:${location.columnNumber}'); } throw ArgumentError( diff --git a/lib/src/run_interactive_codemod.dart b/lib/src/run_interactive_codemod.dart index 09922d1..48c4a09 100644 --- a/lib/src/run_interactive_codemod.dart +++ b/lib/src/run_interactive_codemod.dart @@ -138,7 +138,7 @@ Future runInteractiveCodemodSequence( } return ExitCode.success.code; } - return overrideAnsiOutput>( + return await overrideAnsiOutput>( stdout.supportsAnsiEscapes, () => _runInteractiveCodemod(filePaths, suggestors, parsedArgs, defaultYes: defaultYes, diff --git a/pubspec.yaml b/pubspec.yaml index 2b8124b..bfe4d7e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,10 +7,10 @@ description: > towards updating and refactoring Dart code, but can modify any files. environment: - sdk: '>=2.19.0 <4.0.0' + sdk: ^3.13.0 dependencies: - analyzer: '>=5.13.0 <11.0.0' + analyzer: ^14.0.0 args: ^2.0.0 glob: ^2.0.1 io: ^1.0.0 diff --git a/test/aggregate_suggestor_test.dart b/test/aggregate_suggestor_test.dart index 3ff9f52..695016d 100644 --- a/test/aggregate_suggestor_test.dart +++ b/test/aggregate_suggestor_test.dart @@ -20,12 +20,10 @@ import 'package:test/test.dart'; class MockPatch extends Mock implements Patch {} -@override Stream fooSuggestor(_) async* { yield FooPatch(); } -@override Stream barSuggestor(_) async* { yield BarPatch(); } diff --git a/test/ast_visiting_suggestor_test.dart b/test/ast_visiting_suggestor_test.dart index 739b4dd..312980f 100644 --- a/test/ast_visiting_suggestor_test.dart +++ b/test/ast_visiting_suggestor_test.dart @@ -39,9 +39,9 @@ class Duplicate extends SimpleAstVisitor with AstVisitingSuggestor { class LibNameDoubler extends RecursiveAstVisitor with AstVisitingSuggestor { @override - void visitLibraryIdentifier(LibraryIdentifier node) { - for (final component in node.components) { - yieldPatch(component.name * 2, component.offset, component.end); + void visitDottedName(DottedName node) { + for (final token in node.tokens) { + yieldPatch(token.lexeme * 2, token.offset, token.end); } } } diff --git a/test/functional/run_interactive_codemod_test.dart b/test/functional/run_interactive_codemod_test.dart index 95d984e..8817438 100644 --- a/test/functional/run_interactive_codemod_test.dart +++ b/test/functional/run_interactive_codemod_test.dart @@ -16,6 +16,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:io/io.dart' show ExitCode; import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:test/test.dart'; @@ -200,7 +201,7 @@ void main() { testCodemod( 'quits codemod via prompts when overlapping patches', _afterNoPatches, - expectedExitCode: 255, + expectedExitCode: ExitCode.software.code, stdinLines: ['y', 'y', 'q'], script: 'codemod_overlapping_patches.dart', body: (out, err) { final file1Path = p.canonicalize(d.path('project/file1.txt')); diff --git a/test_fixtures/functional/before/codemod_overlapping_patches.dart b/test_fixtures/functional/before/codemod_overlapping_patches.dart index d5e3e44..94bda45 100644 --- a/test_fixtures/functional/before/codemod_overlapping_patches.dart +++ b/test_fixtures/functional/before/codemod_overlapping_patches.dart @@ -8,7 +8,6 @@ void main(List args) async { args: args); } -@override Stream overlappingPatchSuggestor(FileContext context) async* { yield Patch('overlap', 1, 3); yield Patch('dov', 0, 3);