Proposed auxiliary method wrapAsCustomStyledYamlNode
This probably needs some test cases, and I'm sure the code can be improved further!
void main() {
final doc = YamlEditor('');
doc.update(
[],
wrapAsCustomStyledYamlNode({
'title': 'Short string as title',
'description': [
'Multiple lines with losts of text',
'that you really makes you want',
'the YAML to be written with literal strings',
].join('\n'),
}));
print(doc.toString());
}
YamlNode wrapAsCustomStyledYamlNode(
Object? value, {
CollectionStyle Function(Map map, int depth) styleMap = _defaultMapStyle,
CollectionStyle Function(List list, int depth) styleList = _defaultListStyle,
ScalarStyle Function(String string, int depth) styleString =
_defaultStringStyle,
}) {
YamlNode wrap(Object? value, int depth) {
if (value is YamlScalar) {
wrapAsYamlNode(value); // assert valid scalar
return value;
} else if (value is YamlList) {
for (final item in value.nodes) {
wrapAsYamlNode(item); // assert valid scalar
}
return value;
} else if (value is YamlMap) {
/// Both [entry.key] and [entry.values] are guaranteed to be [YamlNode]s,
/// so running this will just assert that they are valid scalars.
for (final entry in value.nodes.entries) {
wrapAsYamlNode(entry.key);
wrapAsYamlNode(entry.value);
}
return value;
} else if (value is Map) {
return wrapAsYamlNode({
for (final kv in value.entries)
wrap(kv.key, depth + 1): wrap(kv.value, depth + 1),
}, collectionStyle: styleMap(value, depth));
} else if (value is List) {
return wrapAsYamlNode({
for (final v in value) wrap(v, depth + 1),
}, collectionStyle: styleList(value, depth));
} else if (value is String) {
return wrapAsYamlNode(value, scalarStyle: styleString(value, depth));
} else {
return wrapAsYamlNode(value);
}
}
return wrap(value, 0);
}
int _sizeOfScalar(dynamic value) => value == null ? 4 : '$value'.length;
CollectionStyle _defaultMapStyle(Map map, int depth) {
if (map.values.any((value) => value is Map || value is List)) {
return CollectionStyle.BLOCK;
}
final size = map.entries.fold<int>(
0,
(sum, entry) => sum + _sizeOfScalar(entry.key) + _sizeOfScalar(entry.value),
);
if (size < 80) {
return CollectionStyle.FLOW;
}
return CollectionStyle.BLOCK;
}
CollectionStyle _defaultListStyle(List list, int depth) {
if (list.any((value) => value is Map || value is List)) {
return CollectionStyle.BLOCK;
}
final size = list.fold<int>(
0,
(sum, value) => sum + _sizeOfScalar(value),
);
if (size < 80) {
return CollectionStyle.FLOW;
}
return CollectionStyle.BLOCK;
}
ScalarStyle _defaultStringStyle(String string, int depth) {
if (string.contains('\n')) {
return ScalarStyle.LITERAL;
}
if (string.length > 80) {
return ScalarStyle.FOLDED;
}
if (!string.contains('\'')) {
if (!string.contains('"')) {
return ScalarStyle.PLAIN;
}
return ScalarStyle.SINGLE_QUOTED;
}
return ScalarStyle.DOUBLE_QUOTED;
}
Maybe, there needs to be some logic around depth... I suppose it would be nice with an argument that always goes into flow-mode for a depth higher than some threshold, a reasonable default might be 16 (at that point block-mode becomes pretty sketchy to read, I'm just guessing).
I need to try this mr Jonas @jonasfj
@seifibrahim32, please do give it a try.
I think one of the important aspects is to have proper tests. Such that we know that the formatting works, and behaves reasonably.
Perhaps, it'd be a good idea to start with https://github.com/dart-lang/tools/issues/1932 (I just filed it, hehe) But really, adding the functions above is probably not too hard. The hard part is making sure we have tests, so that we're reasonably confident that these things work.
Sure i will try to take a look
Let me take a try :))
@jonasfj I will add some tests if there are \n as mentioned in dart-lang/tools#1932
This function is better since If we used the normal wrapAsYamlNode it wont handle spaces \n or either indentation for scalars.
We need to handle some tests so it clears this method's cases.