tools icon indicating copy to clipboard operation
tools copied to clipboard

Proposed auxiliary method wrapAsCustomStyledYamlNode

Open jonasfj opened this issue 3 years ago • 8 comments

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;
}

jonasfj avatar Dec 21 '22 13:12 jonasfj

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).

jonasfj avatar Dec 21 '22 13:12 jonasfj

I need to try this mr Jonas @jonasfj

seifibrahim32 avatar Feb 09 '23 15:02 seifibrahim32

@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.

jonasfj avatar Feb 10 '23 12:02 jonasfj

Sure i will try to take a look

seifibrahim32 avatar Mar 06 '23 23:03 seifibrahim32

Let me take a try :))

seifibrahim32 avatar Apr 13 '23 14:04 seifibrahim32

@jonasfj I will add some tests if there are \n as mentioned in dart-lang/tools#1932

seifibrahim32 avatar Aug 03 '24 20:08 seifibrahim32

This function is better since If we used the normal wrapAsYamlNode it wont handle spaces \n or either indentation for scalars.

seifibrahim32 avatar Aug 03 '24 21:08 seifibrahim32

We need to handle some tests so it clears this method's cases.

seifibrahim32 avatar Aug 03 '24 21:08 seifibrahim32