dart-lang / yaml_edit

A library for YAML manipulation with comment and whitespace preservation.
https://pub.dev/packages/yaml_edit
BSD 3-Clause "New" or "Revised" License
27 stars 16 forks source link

New API request to replace map key/value pair #18

Open srawlins opened 2 years ago

srawlins commented 2 years ago

I'd love an API (replaceMapEntry?) to replace an entire key/value pair:

final yamlEditor = YamlEditor('''
analyzer:
  foo: false
''');
  yamlEditor.replaceMapEntry(['analyzer', 'foo'], {'bar': true});
  print(yamlEditor);

/*
analyzer:
  bar: true
*/

The current methods for doing this don't work well for us:

I'd be happy to contribute this API!

jonasfj commented 1 year ago

remove foo, add/update bar: results in a flow-style map: analyzer: {foo: false}.

This can be worked around by using wrapAsYamlNode and specify the style.


I have no problems with:

import 'package:yaml/yaml.dart';
import 'package:yaml_edit/yaml_edit.dart';

void main() {
  final yamlEditor = YamlEditor('''
analyzer:
  foo: false
''');
  //yamlEditor.replaceMapEntry(['analyzer', 'foo'], {'bar': true});
  yamlEditor.update(['analyzer', 'bar'], true);
  yamlEditor.remove(['analyzer', 'foo']);
  print(yamlEditor);

  var s = '''
analyzer:
  foo: false
''';

  for (final edit in yamlEditor.edits) {
    s = edit.apply(s);
  }
  print(s);

/*
analyzer:
  bar: true
*/

  final yamlEditor2 = YamlEditor('''
analyzer:
  foo: false
''');
  yamlEditor2.remove(['analyzer', 'foo']);
  yamlEditor2.update(
    ['analyzer'],
    wrapAsYamlNode(
      {'bar': true},
      collectionStyle: CollectionStyle.BLOCK,
    ),
  );
  print(yamlEditor2);

  s = '''
analyzer:
  foo: false
''';

  for (final edit in yamlEditor2.edits) {
    s = edit.apply(s);
  }
  print(s);
}

I'm not sure how the SourceEdits have invalid offsets, I think it's important to apply them in the right order.

jonasfj commented 1 year ago

That said, I can see it being useful to have a method to update a key, but I'm not sure how that isn't just removing an existing key and inserting a new key.

Maybe, the difference is that inserting a new key doesn't put the where the old key was. But I think, yaml_edit will insert keys correctly if they are already in alphabetical order (I think).

But maybe a replace-key makes sense, like yamlEditor.replaceMapEntry(['path', 'to', 'map'], old_key, new_key, value) would make sense. I think having the path being a path to map makes sense, because we usually have a map to the object being modified.

But are we sure it's not better to use the add/remove or remove/add approach? Maybe with wrapAsYamlNode to force styling.