Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(626)

Unified Diff: sdk/lib/convert/json.dart

Issue 224093007: dart:convert: support indented output w/ JsonEncoder (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/lib/convert/json_pretty_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/convert/json.dart
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index 07de8f4caf45eca02a8854464696ca15fae2efe9..5b3474e9d2d836ef1e5b0547358b1362308f3e24 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.dart
@@ -157,6 +157,13 @@ class JsonCodec extends Codec<Object, String> {
* This class converts JSON objects to strings.
*/
class JsonEncoder extends Converter<Object, String> {
+ /**
+ * How many spaces each level of the JSON output is indented.
+ *
+ * If `null`, the output is encoded in a single line.
+ */
+ final int indent;
Lasse Reichstein Nielsen 2014/04/03 18:18:17 Consider letting "indent" be a string which will b
+
final _toEncodableFunction;
/**
@@ -172,7 +179,27 @@ class JsonEncoder extends Converter<Object, String> {
* the object.
*/
const JsonEncoder([Object toEncodable(Object nonSerializable)])
- : this._toEncodableFunction = toEncodable;
+ : this.indent = null,
+ this._toEncodableFunction = toEncodable;
+
+ /**
+ * Creates a JSON encoder with each output level having a specified [indent].
+ *
+ * An encoder with a `null` [indent] encodes objects onto a single line.
+ *
+ * The JSON encoder handles numbers, strings, booleans, null, lists and
+ * maps directly.
+ *
+ * Any other object is attempted converted by [toEncodable] to an
+ * object that is of one of the convertible types.
+ *
+ * If [toEncodable] is omitted, it defaults to calling `.toJson()` on
+ * the object.
+ */
+ const JsonEncoder.withIndent(int indent,
+ [Object toEncodable(Object nonSerializable)])
+ : this.indent = indent != null && indent < 0 ? 0 : indent,
+ this._toEncodableFunction = toEncodable;
/**
* Converts the given object [o] to its JSON representation.
@@ -202,7 +229,7 @@ class JsonEncoder extends Converter<Object, String> {
* serialized, the new values may or may not be reflected in the result.
*/
String convert(Object o) =>
- _JsonStringifier.stringify(o, _toEncodableFunction);
+ _JsonStringifier.stringify(o, _toEncodableFunction, indent);
/**
* Starts a chunked conversion.
@@ -217,7 +244,7 @@ class JsonEncoder extends Converter<Object, String> {
if (sink is! StringConversionSink) {
sink = new StringConversionSink.from(sink);
}
- return new _JsonEncoderSink(sink, _toEncodableFunction);
+ return new _JsonEncoderSink(sink, _toEncodableFunction, indent);
}
// Override the base-classes bind, to provide a better type.
@@ -230,11 +257,12 @@ class JsonEncoder extends Converter<Object, String> {
* The sink only accepts one value, but will produce output in a chunked way.
*/
class _JsonEncoderSink extends ChunkedConversionSink<Object> {
+ final int _indent;
final Function _toEncodableFunction;
final StringConversionSink _sink;
bool _isDone = false;
- _JsonEncoderSink(this._sink, this._toEncodableFunction);
+ _JsonEncoderSink(this._sink, this._toEncodableFunction, this._indent);
/**
* Encodes the given object [o].
@@ -249,7 +277,7 @@ class _JsonEncoderSink extends ChunkedConversionSink<Object> {
}
_isDone = true;
ClosableStringSink stringSink = _sink.asStringSink();
- _JsonStringifier.printOn(o, stringSink, _toEncodableFunction);
+ _JsonStringifier.printOn(o, stringSink, _toEncodableFunction, _indent);
stringSink.close();
}
@@ -353,19 +381,24 @@ class _JsonStringifier {
final StringSink _sink;
final List _seen;
- _JsonStringifier(this._sink, this._toEncodable)
+ factory _JsonStringifier(StringSink sink, Function toEncodable, int indent) {
+ if (indent == null) return new _JsonStringifier._(sink, toEncodable);
+ return new _JsonStringifierPretty(sink, toEncodable, indent);
+ }
+
+ _JsonStringifier._(this._sink, this._toEncodable)
: this._seen = new List();
- static String stringify(object, toEncodable(object)) {
+ static String stringify(object, toEncodable(object), int indent) {
if (toEncodable == null) toEncodable = _defaultToEncodable;
StringBuffer output = new StringBuffer();
- printOn(object, output, toEncodable);
+ printOn(object, output, toEncodable, indent);
return output.toString();
}
- static void printOn(object, StringSink output, toEncodable(object)) {
- _JsonStringifier stringifier = new _JsonStringifier(output, toEncodable);
- stringifier.stringifyValue(object);
+ static void printOn(object, StringSink output, toEncodable(object),
+ int indent) {
+ new _JsonStringifier(output, toEncodable, indent).stringifyValue(object);
}
static String numberToString(num x) {
@@ -515,3 +548,83 @@ class _JsonStringifier {
_seen.removeLast();
}
}
+
+
+class _JsonStringifierPretty extends _JsonStringifier {
+
+ final String _indent;
+
+ int _indentLevel = 0;
+
+ _JsonStringifierPretty(_sink, _toEncodable, int indent)
+ : this._indent = _getIndent(indent),
+ super._(_sink, _toEncodable);
+
+ static String _getIndent(int indent) {
+ if (indent < 0) throw new ArgumentError('indent cannot be negative');
+ return ' ' * indent;
+ }
+
+ void _write([String value = '']) {
+ _sink.write(_indent * _indentLevel);
+ _sink.write(value);
+ }
+
+ /**
+ * Serializes a [num], [String], [bool], [Null], [List] or [Map] value.
+ *
+ * Returns true if the value is one of these types, and false if not.
+ * If a value is both a [List] and a [Map], it's serialized as a [List].
+ */
+ bool stringifyJsonValue(final object) {
+ if (object is List) {
+ checkCycle(object);
+ List a = object;
+ if (a.isEmpty) {
+ _sink.write('[]');
+ } else {
+ _sink.writeln('[');
+ _indentLevel++;
+ _write();
+ stringifyValue(a[0]);
+ for (int i = 1; i < a.length; i++) {
+ _sink.writeln(',');
+ _write();
+ stringifyValue(a[i]);
+ }
+ _sink.writeln();
+ _indentLevel--;
+ _write(']');
+ }
+ _seen.remove(object);
+ return true;
+ } else if (object is Map) {
+ checkCycle(object);
+ Map<String, Object> m = object;
+ if (m.isEmpty) {
+ _sink.write('{}');
+ } else {
+ _sink.write('{');
+ _sink.writeln();
+ _indentLevel++;
+ bool first = true;
+ m.forEach((String key, Object value) {
+ if (!first) {
+ _sink.writeln(',');
+ }
+ _write('"');
+ escape(key);
+ _sink.write('": ');
+ stringifyValue(value);
+ first = false;
+ });
+ _sink.writeln();
+ _indentLevel--;
+ _write('}');
+ }
+ _seen.remove(object);
+ return true;
+ }
+ return super.stringifyJsonValue(object);
+ }
+}
« no previous file with comments | « no previous file | tests/lib/convert/json_pretty_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698