blob: 5aef4dc049f243d2c354876861da5366185dc7ea [file] [log] [blame]
// 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 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:dart_style/dart_style.dart';
import 'analyzer_patch.dart';
final _dartFmt = new DartFormatter();
/// Returns [source] formatted by `dartfmt`.
String dartfmt(String source) {
try {
return _dartFmt.format(source);
} on FormatterException catch (_) {
return _dartFmt.formatStatement(source);
}
}
/// Augments [AstNode.toSource] by adding some whitespace/line breaks.
///
/// The final result is run through `dartfmt`.
///
/// This is the _recommended_ output (but not required) when comparing ASTs
/// to expected golden files/text blobs.
String prettyToSource(AstNode astNode) {
var buffer = new PrintBuffer();
var visitor = new _PrettyToSourceVisitor(buffer);
astNode.accept(visitor);
var source = buffer.toString();
try {
return dartfmt(source);
} on FormatterException catch (_) {
return source;
}
}
// https://github.com/dart-lang/code_builder/issues/16
class _PrettyToSourceVisitor extends ToSourceVisitor {
final StringBuffer _buffer;
_PrettyToSourceVisitor(PrintBuffer buffer)
: _buffer = buffer,
super(buffer);
@override
Object visitClassDeclaration(ClassDeclaration node) {
_visitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
_visitTokenWithSuffix(node.abstractKeyword, " ");
_buffer.write("class ");
_visitNode(node.name);
_visitNode(node.typeParameters);
_visitNodeWithPrefix(" ", node.extendsClause);
_visitNodeWithPrefix(" ", node.withClause);
_visitNodeWithPrefix(" ", node.implementsClause);
_buffer.write(" {");
_visitNodeListWithSeparator(node.members, "\n\n");
_buffer.write("}");
return null;
}
// Safely visit the given [node].
void _visitNode(AstNode node) {
if (node != null) {
node.accept(this);
}
}
// Write a list of [nodes], separated by the given [separator].
void _visitNodeListWithSeparator(NodeList<AstNode> nodes, String separator) {
if (nodes != null) {
int size = nodes.length;
for (int i = 0; i < size; i++) {
if (i > 0) {
_buffer.write(separator);
}
nodes[i].accept(this);
}
}
}
// Write a list of [nodes], separated by the given [separator], followed by
// the given [suffix] if the list is not empty.
void _visitNodeListWithSeparatorAndSuffix(
NodeList<AstNode> nodes,
String separator,
String suffix,
) {
if (nodes != null) {
int size = nodes.length;
if (size > 0) {
for (int i = 0; i < size; i++) {
if (i > 0) {
_buffer.write(separator);
}
nodes[i].accept(this);
}
_buffer.write(suffix);
}
}
}
// Safely visit the given [node], writing the [prefix] before the node if it
// is non-`null`.
void _visitNodeWithPrefix(String prefix, AstNode node) {
if (node != null) {
_buffer.write(prefix);
node.accept(this);
}
}
// Safely visit the given [token], writing the [suffix] after the token if it
// is non-`null`.
void _visitTokenWithSuffix(Token token, String suffix) {
if (token != null) {
_buffer.write(token.lexeme);
_buffer.write(suffix);
}
}
}