blob: 69953d0c65860d68ce39861e6324f72da8675b5a [file] [edit]
import 'dart:io' as io;
import 'package:analyzer/dart/analysis/analysis_context_collection.dart'
as analyzer;
import 'package:analyzer/dart/analysis/formatter_options.dart' as analyzer;
import 'package:analyzer/dart/analysis/results.dart' as analyzer;
import 'package:analyzer/file_system/file_system.dart' as analyzer;
import 'package:analyzer/file_system/physical_file_system.dart' as analyzer;
import 'package:path/path.dart' as p;
import 'cli/formatter_options.dart';
import 'dart_formatter.dart';
import 'exceptions.dart';
import 'source_code.dart';
// TODO: Allow this to be configured.
final analyzer.ResourceProvider resourceProvider =
analyzer.PhysicalResourceProvider.INSTANCE;
Future<void> formatPaths(FormatterOptions options, List<String> paths) async {
var filesToFormat = <(String, String)>[];
for (var path in paths) {
var directory = io.Directory(path);
if (directory.existsSync()) {
var entries = directory.listSync(
recursive: true,
followLinks: options.followLinks,
);
entries.sort((a, b) => a.path.compareTo(b.path));
for (var entry in entries) {
if (entry is io.Link) continue;
if (entry is! io.File || !entry.path.endsWith('.dart')) continue;
// If the path is in a subdirectory starting with ".", ignore it.
var parts = p.split(p.relative(entry.path, from: directory.path));
if (parts.any((part) => part.startsWith('.'))) continue;
filesToFormat.add((p.normalize(p.absolute(entry.path)), entry.path));
}
} else {
var file = io.File(path);
if (file.existsSync()) {
filesToFormat.add((p.normalize(p.absolute(file.path)), file.path));
} else {
io.stderr.writeln('No file or directory found at "$path".');
}
}
}
var collection = analyzer.AnalysisContextCollection(
includedPaths: filesToFormat.map((r) => r.$1).toList(),
);
print('Should format ${filesToFormat.length}');
for (var (path, displayPath) in filesToFormat) {
await _processFile(collection, options, path, displayPath: displayPath);
}
await collection.dispose();
}
/// Runs the formatter on [file].
///
/// Returns `true` if successful or `false` if an error occurred.
Future<bool> _processFile(
analyzer.AnalysisContextCollection collection,
FormatterOptions options,
String path, {
String? displayPath,
}) async {
displayPath ??= path;
var context = collection.contextFor(path);
var analysisOptions = context.getAnalysisOptionsForFile(
resourceProvider.getFile(path),
);
var session = context.currentSession;
var parsedResult = session.getParsedUnit(path);
if (parsedResult is! analyzer.ParsedUnitResult) {
// TODO
throw StateError('not parsed result');
}
// Determine what language version to use.
// TODO: Use .effective?
var languageVersion =
options.languageVersion ?? parsedResult.unit.languageVersion.package;
// Determine the configuration options.
var pageWidth =
options.pageWidth ?? analysisOptions.formatterOptions.pageWidth;
var trailingCommas =
options.trailingCommas ??
switch (analysisOptions.formatterOptions.trailingCommas) {
null => TrailingCommas.automate,
analyzer.TrailingCommas.automate => TrailingCommas.automate,
analyzer.TrailingCommas.preserve => TrailingCommas.preserve,
};
// Use a default page width if we don't have a specified one and couldn't
// find a configured one.
pageWidth ??= DartFormatter.defaultPageWidth;
var formatter = DartFormatter(
languageVersion: languageVersion,
indent: options.indent,
pageWidth: pageWidth,
trailingCommas: trailingCommas,
experimentFlags: options.experimentFlags,
);
try {
var source = SourceCode(
resourceProvider.getFile(path).readAsStringSync(),
uri: path,
);
options.beforeFile(path, displayPath);
var output = formatter.formatUnit(parsedResult);
options.afterFile(
path,
formatter,
displayPath,
output,
changed: source.text != output.text,
);
return true;
} on FormatterException catch (err) {
var color =
io.Platform.operatingSystem != 'windows' &&
io.stdioType(io.stderr) == io.StdioType.terminal;
io.stderr.writeln(err.message(color: color));
} on UnexpectedOutputException catch (err) {
io.stderr.writeln(
'''Hit a bug in the formatter when formatting $displayPath.
$err
Please report at github.com/dart-lang/dart_style/issues.''',
);
} catch (err, stack) {
io.stderr.writeln(
'''Hit a bug in the formatter when formatting $displayPath.
Please report at github.com/dart-lang/dart_style/issues.
$err
$stack''',
);
}
return false;
}