Skip to content

Commit

Permalink
Renaming: import->directive
Browse files Browse the repository at this point in the history
  • Loading branch information
regenvanwalbeek-wf committed Jul 21, 2022
1 parent 37fe8de commit 17d6e60
Show file tree
Hide file tree
Showing 22 changed files with 372 additions and 409 deletions.
8 changes: 4 additions & 4 deletions doc/tools/format-tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,18 @@ final config = {
};
```

### Organizing imports
### Organizing directives

By default, the format tool will not sort imports. Imports can be automatically
sorted by setting `organizeImports`.
By default, the format tool will not sort imports/export. They can be automatically
sorted by setting `organizeDirectives`.

```dart
// tool/dart_dev/config.dart
import 'package:dart_dev/dart_dev.dart';
final config = {
'format': FormatTool()
..organizeImports = true
..organizeDirectives = true
};
```

Expand Down
42 changes: 21 additions & 21 deletions lib/src/tools/format_tool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import '../dart_dev_tool.dart';
import '../utils/arg_results_utils.dart';
import '../utils/assert_no_positional_args_nor_args_after_separator.dart';
import '../utils/logging.dart';
import '../utils/organize_imports/organize_imports_in_paths.dart';
import '../utils/organize_directives/organize_directives_in_paths.dart';
import '../utils/package_is_immediate_dependency.dart';
import '../utils/process_declaration.dart';
import '../utils/run_process_and_ensure_exit.dart';
Expand Down Expand Up @@ -69,10 +69,10 @@ class FormatTool extends DevTool {
/// Run `dartfmt -h -v` to see all available args.
List<String> formatterArgs;

/// If the formatter should also organize imports.
/// If the formatter should also organize imports and exports.
///
/// By default, this is disabled.
bool organizeImports = false;
bool organizeDirectives = false;

// ---------------------------------------------------------------------------
// DevTool Overrides
Expand Down Expand Up @@ -111,7 +111,7 @@ class FormatTool extends DevTool {
defaultMode: defaultMode,
exclude: exclude,
formatter: formatter,
organizeImports: organizeImports,
organizeDirectives: organizeDirectives,
);
if (formatExecution.exitCode != null) {
return formatExecution.exitCode;
Expand All @@ -123,10 +123,10 @@ class FormatTool extends DevTool {
if (exitCode != 0) {
return exitCode;
}
if (formatExecution.importOrganization != null) {
exitCode = organizeImportsInPaths(
formatExecution.importOrganization.inputs,
check: formatExecution.importOrganization.check,
if (formatExecution.directiveOrganization != null) {
exitCode = organizeDirectivesInPaths(
formatExecution.directiveOrganization.inputs,
check: formatExecution.directiveOrganization.check,
verbose: context.verbose,
);
}
Expand Down Expand Up @@ -314,8 +314,8 @@ class FormatterInputs {
class FormatExecution {
FormatExecution.exitEarly(this.exitCode)
: formatProcess = null,
importOrganization = null;
FormatExecution.process(this.formatProcess, [this.importOrganization])
directiveOrganization = null;
FormatExecution.process(this.formatProcess, [this.directiveOrganization])
: exitCode = null;

/// If non-null, the execution is already complete and the [FormatTool] should
Expand All @@ -329,14 +329,14 @@ class FormatExecution {
/// If this process results in a non-zero exit code, [FormatTool] should return it.
final ProcessDeclaration formatProcess;

/// A declarative representation of the import organization work to be done
/// A declarative representation of the directive organization work to be done
/// (if enabled) after running the formatter.
final ImportOrganization importOrganization;
final DirectiveOrganization directiveOrganization;
}

/// A declarative representation of the import organization work.
class ImportOrganization {
ImportOrganization(this.inputs, {this.check});
/// A declarative representation of the directive organization work.
class DirectiveOrganization {
DirectiveOrganization(this.inputs, {this.check});

final bool check;
final Set<String> inputs;
Expand Down Expand Up @@ -423,7 +423,7 @@ Iterable<String> buildArgs(
///
/// [include] will be populated from [FormatTool.include].
///
/// [organizeImports] will be populated from [FormatTool.organizeImports].
/// [organizeDirectives] will be populated from [FormatTool.organizeDirectives].
///
/// If non-null, [path] will override the current working directory for any
/// operations that require it. This is intended for use by tests.
Expand All @@ -437,7 +437,7 @@ FormatExecution buildExecution(
FormatMode defaultMode,
List<Glob> exclude,
Formatter formatter,
bool organizeImports = false,
bool organizeDirectives = false,
String path,
}) {
FormatMode mode;
Expand Down Expand Up @@ -516,16 +516,16 @@ FormatExecution buildExecution(
[...args, ...inputs.includedFiles],
mode: ProcessStartMode.inheritStdio,
);
ImportOrganization importOrganization;
if (organizeImports) {
importOrganization = ImportOrganization(
DirectiveOrganization directiveOrganization;
if (organizeDirectives) {
directiveOrganization = DirectiveOrganization(
inputs.includedFiles,
check: mode == FormatMode.check,
);
}
return FormatExecution.process(
formatProcess,
importOrganization,
directiveOrganization,
);
}

Expand Down
76 changes: 76 additions & 0 deletions lib/src/utils/organize_directives/namespace.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';

/// A representation of an namespace directive.
///
/// Capable of tracking comments that should be associated with an namespace
/// during organization (which cannot be represented by the AST)
class Namespace {
/// The AST node that represents an namespace in a file.
final NamespaceDirective directive;

/// Comments that appear before the namespace that should stay with the
/// namespace when organized.
List<Token> beforeComments = [];

/// Comments that appear after the namespace that should stay with the
/// namespace when organized.
List<Token> afterComments = [];

/// The file being imported/exported.
String get target {
return directive.uri.stringValue;
}

/// If the namespace is a dart namespace. Memoized for performance.
bool _isDart;
bool get isDart {
return _isDart ??= target.startsWith('dart:');
}

/// If the namespace is an external package namespace. Memoized for performance.
bool _isExternalPkg;
bool get isExternalPkg {
return _isExternalPkg ??= target.startsWith('package:');
}

/// If the namespace is a relative namespace. Memoized for performance.
bool _isRelative;
bool get isRelative {
return _isRelative ??= !isExternalPkg && !isDart;
}

Namespace(this.directive);

/// The character offset of the start of the namespace statement in source text.
/// Excludes comments associated with this namespace.
int get statementStart => directive.beginToken.charOffset;

/// The character offset of the end of the namespace statement in source text.
/// Excludes comments associated with this namespace.
int get statementEnd => directive.endToken.end;

/// The character offset of the end of this namespace in source text.
/// Includes comments associated with this namespace.
int end() {
var end = directive.endToken.end;
for (final afterComment in afterComments) {
if (afterComment.end > end) {
end = afterComment.end;
}
}
return end;
}

/// The character offset of the start of this namespace in source text.
/// Includes comments associated with this namespace.
int start() {
var charOffset = directive.beginToken.charOffset;
for (final beforeComment in beforeComments) {
if (beforeComment.charOffset < charOffset) {
charOffset = beforeComment.charOffset;
}
}
return charOffset;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'namespace_collector.dart';
/// Sorts imports/exports and removes double quotes.
///
/// Throws an ArgumentError if [sourceFileContents] cannot be parsed.
String organizeImports(String sourceFileContents) {
String organizeDirectives(String sourceFileContents) {
final directives = parseString(content: sourceFileContents)
.unit
.accept(NamespaceCollector());
Expand Down Expand Up @@ -79,14 +79,15 @@ String _organizeDirectivesOfType<T>(
/// Puts comments in a source file with the correct namespace directive so they
/// can be moved with the directive when sorted.
///
/// The parser puts "precedingComments" on each token. However, an import's
/// The parser puts "precedingComments" on each token. However, a directive's
/// precedingComments shouldn't necessarily be the comments that move with the
/// import during a sort. If an import has a trailing comment on the same line
/// as an import, it will be attached to the next Token's "precedingComments".
/// directive during a sort. If a directive has a trailing comment on the same
/// line as a directive, it will be attached to the next Token's
/// "precedingComments".
///
/// For this reason, we go thru all imports (and the first token after the last
/// import), look at their precedingComments, and determine which import they
/// belong to.
/// For this reason, we go thru all directives (and the first token after the
/// last directive), look at their precedingComments, and determine which
/// directive they belong to.
List<Namespace> _assignCommentsInFileToNamespaceDirective(
String sourceFileContents,
List<NamespaceDirective> directives,
Expand All @@ -108,8 +109,8 @@ List<Namespace> _assignCommentsInFileToNamespaceDirective(
prevNamespace = currNamespace;
}

// Assign comments after the last import to the last import if they are on
// the same line.
// Assign comments after the last directive to the last directive if they are
// on the same line.
_assignCommentsBeforeTokenToNamespace(
prevNamespace.directive.endToken.next,
sourceFileContents,
Expand Down Expand Up @@ -141,8 +142,8 @@ void _assignCommentsBeforeTokenToNamespace(
}
}

/// Checks if a given comment is on the same line as an import.
/// It's expected that import end is before comment start.
/// Checks if a given comment is on the same line as a directive.
/// It's expected that directive end is before comment start.
bool _commentIsOnSameLineAsNamespace(
Token comment, Namespace namespace, String sourceFileContents) {
return namespace != null &&
Expand All @@ -157,51 +158,51 @@ String _getSortedNamespaceString(
List<Namespace> namespaces,
) {
final sortedReplacement = StringBuffer();
final firstRelativeImportIdx =
namespaces.indexWhere((import) => import.isRelativeImport);
final firstPkgImportIdx =
namespaces.indexWhere((import) => import.isExternalPkgImport);
for (var importIndex = 0; importIndex < namespaces.length; importIndex++) {
final import = namespaces[importIndex];
if (importIndex != 0 &&
(importIndex == firstRelativeImportIdx ||
importIndex == firstPkgImportIdx)) {
final firstRelativeNamespaceIdx =
namespaces.indexWhere((namespace) => namespace.isRelative);
final firstPkgDirectiveIdx =
namespaces.indexWhere((namespace) => namespace.isExternalPkg);
for (var nsIndex = 0; nsIndex < namespaces.length; nsIndex++) {
final namespace = namespaces[nsIndex];
if (nsIndex != 0 &&
(nsIndex == firstRelativeNamespaceIdx ||
nsIndex == firstPkgDirectiveIdx)) {
sortedReplacement.write('\n');
}
final importDirectiveWithQuotesReplaced = sourceFileContents
.substring(import.statementStart, import.statementEnd)
final namespaceWithQuotesReplaced = sourceFileContents
.substring(namespace.statementStart, namespace.statementEnd)
.replaceAll('"', "'");

final source = sourceFileContents
.replaceRange(
import.statementStart,
import.statementEnd,
importDirectiveWithQuotesReplaced,
namespace.statementStart,
namespace.statementEnd,
namespaceWithQuotesReplaced,
)
.substring(import.start(), import.end());
.substring(namespace.start(), namespace.end());
sortedReplacement..write(source)..write('\n');
}
return sortedReplacement.toString();
}

/// A comparator that will sort dart imports first, then package imports, then
/// relative imports.
/// A comparator that will sort dart directives first, then package directives,
/// then relative directives.
int _namespaceComparator(Namespace first, Namespace second) {
if (first.isDartImport && second.isDartImport) {
if (first.isDart && second.isDart) {
return first.target.compareTo(second.target);
}

if (first.isDartImport && !second.isDartImport) {
if (first.isDart && !second.isDart) {
return -1;
}

if (!first.isDartImport && second.isDartImport) {
if (!first.isDart && second.isDart) {
return 1;
}

// Neither are dart imports
final firstIsPkg = first.isExternalPkgImport;
final secondIsPkg = second.isExternalPkgImport;
// Neither are dart directives
final firstIsPkg = first.isExternalPkg;
final secondIsPkg = second.isExternalPkg;
if (firstIsPkg && secondIsPkg) {
return first.target.compareTo(second.target);
}
Expand All @@ -214,6 +215,6 @@ int _namespaceComparator(Namespace first, Namespace second) {
return 1;
}

// Neither are dart imports or pkg imports. Must be relative path imports...
// Neither are dart directives or pkg directives. Must be relative path directives...
return first.target.compareTo(second.target);
}
Loading

0 comments on commit 17d6e60

Please sign in to comment.