Skip to content
This repository has been archived by the owner on May 25, 2022. It is now read-only.

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
Matan Lurey committed Dec 19, 2016
0 parents commit 731e6d3
Show file tree
Hide file tree
Showing 19 changed files with 785 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .analysis_options
@@ -0,0 +1,28 @@
analyzer:
strong-mode: true
linter:
rules:
# Errors
- avoid_empty_else
- control_flow_in_finally
- empty_statements
- test_types_in_equals
- throw_in_finally
- valid_regexps

# Style
- annotate_overrides
- avoid_init_to_null
- avoid_return_types_on_setters
- await_only_futures
- camel_case_types
- comment_references
- empty_catches
- empty_constructor_bodies
- hash_and_equals
- library_prefixes
- non_constant_identifier_names
- prefer_is_not_empty
- slash_for_doc_comments
- type_init_formals
- unrelated_type_equality_checks
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
.packages
.pub
pubspec.lock
13 changes: 13 additions & 0 deletions bin/deduplicate.dart
@@ -0,0 +1,13 @@
import 'package:source_transformer/source_transformer.dart';

/// Remove all duplicate imports and exports in a set of files.
///
/// Simple but useful example of consuming a source transformer.
///
/// ## Example use
/// ```
/// $ dart bin/deduplicate.dart /some/path.dart /some/other/path.dart ...
/// ```
main(List<String> paths) async {
await runTransformer(const DeduplicateDirectives(), paths);
}
11 changes: 11 additions & 0 deletions lib/source_transformer.dart
@@ -0,0 +1,11 @@
export 'package:source_transformer/src/cli.dart' show runTransformer;
export 'package:source_transformer/src/dart/directives.dart'
show
DeduplicateDirectives,
DirectiveTransformer,
RemoveDirectives,
ReplaceDirectives;
export 'package:source_transformer/src/patch.dart' show Patch;
export 'package:source_transformer/src/phase.dart' show Phase;
export 'package:source_transformer/src/transformer.dart'
show DartSourceTransformer, Transformer;
25 changes: 25 additions & 0 deletions lib/src/cli.dart
@@ -0,0 +1,25 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:io';

import 'package:source_span/source_span.dart';
import 'package:source_transformer/source_transformer.dart';

/// Convenience function to run a [transformer] on the provided file [paths].
///
/// See `bin/deduplicate.dart` for an example.
Future runTransformer(
Transformer transformer,
Iterable<String> paths,
) {
return Future.wait(paths.map((path) async {
final input = new File(path);
final sourceText = input.readAsStringSync();
final oldFile = new SourceFile(sourceText, url: path);
final newFile = await transformer.transform(oldFile);
input.writeAsStringSync(newFile.getText(0));
}));
}
123 changes: 123 additions & 0 deletions lib/src/dart/directives.dart
@@ -0,0 +1,123 @@
// Copyright (c) 2016, 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.
library source_transformer.src.dart.directives;

import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:source_transformer/source_transformer.dart';
import 'package:source_transformer/src/utils.dart';

part 'directives/equality.dart';
part 'directives/transformer.dart';

/// A transformer that removes duplicate import and export directives.
///
/// The default implementation of `Equality<Directive>` only attempts to remove
/// directives without deferred loading, an `as` statement, or the `show` and
/// `hide` combinators.
///
/// An ideal transformer to run after refactoring directives.
class DeduplicateDirectives extends DirectiveTransformer<Set<Directive>> {
final Equality<Directive> _equality;

@literal
const DeduplicateDirectives({
Equality<Directive> equality: const DirectiveEquality(),
})
: _equality = equality;

@override
bool canTransform(Directive directive) {
if (directive is ImportDirective) {
return directive.asKeyword == null &&
directive.deferredKeyword == null &&
directive.combinators == null ||
directive.combinators.isEmpty;
}
if (directive is ExportDirective) {
return directive.combinators == null || directive.combinators.isEmpty;
}
return false;
}

@override
Set<Directive> defaultState() => new EqualitySet<Directive>(_equality);

@override
Directive transformDirective(Directive directive, [Set<Directive> state]) {
return state.add(directive) ? directive : null;
}
}

/// A source transformer that removes directives that reference certain URIs.
///
/// If a URI is not found, it is skipped.
///
/// ## Example use
/// ```
/// const RemoveDirectives([
/// 'package:a/a.dart',
/// 'package:b/b.dart',
/// ])
/// ```
class RemoveDirectives extends DirectiveTransformer<Null> {
final Iterable<String> _uris;

@literal
const RemoveDirectives(this._uris);

@mustCallSuper
@override
bool canTransform(Directive directive) {
if (directive is UriBasedDirective) {
return _uris.contains(directive.uri.stringValue);
}
return false;
}

@override
Directive transformDirective(@checked UriBasedDirective directive, [_]) {
return null;
}
}

/// A source transformer that replaces directives with other URIs.
///
/// ## Example use
/// ```
/// const ReplaceDirectives({
/// 'package:a/a.dart': 'package:b/b.dart',
/// })
/// ```
class ReplaceDirectives extends DirectiveTransformer<Null> {
final Map<String, String> _uris;

const ReplaceDirectives(this._uris);

@mustCallSuper
@override
bool canTransform(Directive directive) {
if (directive is UriBasedDirective) {
return _uris.containsKey(directive.uri.stringValue);
}
return false;
}

@override
Directive transformDirective(@checked UriBasedDirective directive, [_]) {
final newUri = _uris[directive.uri.stringValue];
if (newUri != null) {
return cloneNode(directive)
..uri = astFactory.simpleStringLiteral(
new StringToken(TokenType.STRING, "'$newUri'", 0),
"'$newUri'",
);
}
return directive;
}
}
39 changes: 39 additions & 0 deletions lib/src/dart/directives/equality.dart
@@ -0,0 +1,39 @@
// Copyright (c) 2016, 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.
part of source_transformer.src.dart.directives;

class DirectiveEquality implements Equality<Directive> {
const DirectiveEquality();

@override
bool equals(Directive e1, Directive e2) {
if (e1 is ImportDirective && e2 is ImportDirective) {
if (e1.asKeyword != null ||
e1.deferredKeyword != null ||
e1.combinators?.isNotEmpty == true ||
e2.asKeyword != null ||
e2.deferredKeyword != null ||
e2.combinators?.isNotEmpty == true) {
// For now don't try to compare import directive properties.
return false;
}
return e1.uri.stringValue == e2.uri.stringValue;
}
if (e1 is ExportDirective && e2 is ExportDirective) {
if (e1.combinators?.isNotEmpty == true ||
e2.combinators?.isNotEmpty == true) {
// For now don't try to compare import directive properties.
return false;
}
return e1.uri.stringValue == e2.uri.stringValue;
}
return false;
}

@override
int hash(Directive e) => e.toSource().hashCode;

@override
bool isValidKey(Object o) => o is Directive;
}
38 changes: 38 additions & 0 deletions lib/src/dart/directives/transformer.dart
@@ -0,0 +1,38 @@
// Copyright (c) 2016, 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.
part of source_transformer.src.dart.directives;

/// A high-level transformer for manipulating `import` and `export` directives.
abstract class DirectiveTransformer<S> extends DartSourceTransformer {
const DirectiveTransformer();

/// Should return `true` if the directive should be altered.
@protected
bool canTransform(Directive directive);

/// Return a new default state object; optional.
@protected
S defaultState() => null;

@override
Iterable<Patch> computePatches(CompilationUnit parsedSource) {
final initialState = defaultState();
return parsedSource.directives.where(canTransform).map((oldDirective) {
final newDirective = transformDirective(oldDirective, initialState);
if (newDirective == null) {
return new Patch.removeAst(oldDirective);
}
return new Patch.replaceAst(oldDirective, newDirective);
});
}

/// Returns a new directive to replace [directive] with.
///
/// May return back the _same_ directive to avoid doing anything, but if
/// possible it is preferred to make this type of check in [canTransform].
///
/// If `null` is returned, indicates that directive should be removed.
@protected
Directive transformDirective(Directive directive, [S state]);
}

0 comments on commit 731e6d3

Please sign in to comment.