walnutdust / yaml_edit

A dart library for YAML manipulation
0 stars 0 forks source link

YAML Style Configurations #2

Open walnutdust opened 4 years ago

walnutdust commented 4 years ago

Implementation of a class that allows the user of the library to define the default options that will be used when the library modifies the YAML string.

This involves:

  1. Understanding styling options that users might want to use
  2. Incorporating them into the code.
  3. Understanding the methods a class like this could have, e.g.
    YamlEditBuilderConfig someConfig = ...
    YamlEditBuilderConfig updatedConfig = someConfig.with(enforceFlow: true);

    Examples of these style configurations include:

    • indentationStep - number of additional spaces between block elements at adjacent levels
    • enforceFlow - whether to always use flow styling, or to try to use block where possible.

In addition, we might want to consider modifying the mutation methods to allow the user to specify settings for a specific mutation.

walnutdust commented 4 years ago

Two (three?) proposals on how styling can happen.

Proposal 1: YAML Styling Options

Allow user-defined custom styling options for YAML mutations for the session as well as for individual mutations.

Users may have a preference for a specific formatting option that they wish to apply to the document as they perform mutations. We allow this by initializing YamlEditor with a YamlStyle class that defines the following options. Individual mutation operations will also take in an additional optional named argument style that allows for a YamlStyle to be defined for a specific mutation operation.

Options

  1. indentationStep (positive int) - Determines the number of spaces per YAML depth level.

2a. flowLevel (non-negative int) - Nested collections at depth flowLevel or greater will have flow styling enforced when elements are added into the YAML document. For example, a flowLevel of 2 looks like:

a:
  b: [c, d, [e, f]]

This does not mean that elements before the second level cannot be styled in flow styling. For example, if our original document was:

[1, 2, 3]

It is clear to see that any addition/update of elements into this YAML document has to take on flow styling since we cannot have block styling in flow structures. Note that this option will likely be mutually exclusive with 2b. This might be a more flexible alternative to 2b, since it allows for more customization, and it makes more sense (too many nested block structures will eat up line width). We can define flowLevel (or give it a better name) to be with respect to the base level when used to initialize YamlEditor, or with respect to the collection passed in when used in a mutation method.

2b. enforceFlow (bool) - If true, collections added will have flow styling enforced. If false, collections will default to block styling where possible. Note that this option will likely be mutually exclusive with 2a.

  1. scalarStyle (ScalarStyle from package:yaml) - Sets the default style to be used for scalars where possible. Cases where this might not work include where the style is set to plain, and the scalar is a string beginning with ', ", >, or could be interpreted as a boolean/null (e.g. true).

Considerations

As far as this proposal is concerned, these styling options will only be applied to the regions of the YAML affected by mutations. Original YAML text will not be affected.

Proposal 1b: style collection

An extension of Proposal 1, instead of the mutation methods receiving YamlStyle objects for a custom style to be used for the specific mutation, we allow the user to pass in a collection that mimics the structure of the collection or item passed in. For example, if a list [Jan, Feb, Mar, Apr] were to be passed in, the style argument could take something like:

{
  #style: CollectionStyle.BLOCK,
  #indentation: 2,
  children: [
                   'Jan': { #style: CollectionStyle.SINGLE_QUOTE, #indentation: 2}
                      ...
                 ]
}

Which should allow for maximum flexibility at the cost of being verbose.

Proposal 2: YAML Formatter

There might not be as much value in allowing the user too much flexibility within the individual mutations. Rather, we can try to provide an opinionated yaml formatter service that could run before toString() is called, which could try to align text:

one: 1
two:     2
three:     3

could become:

one: 1
two: 2
three: 3

or

one:   1
two:   2
three: 3

, make everything with a defined indentation step, and possibly wrap folded and literal strings to a certain line width.

This might also be useful in creating canonical output, although at the potential loss of some (probably non-essential) whitespace.

Will have to experiment to see how feasible this is.

Other things considered

walnutdust commented 4 years ago

@jonasfj some preliminary thoughts above! Would love to hear what you think!

jonasfj commented 4 years ago

@walnutdust, in YamlEdit.assign(path, value) do we allow value to be a instance of YamlNode. If so I suggest we patch package:yaml, such that we have wrap constructors:

Adding an extra optional parameter won't break anyone. If users really want to control nested style they can then do:

yamlEdit.assign(path, YamlMap.wrap({
  'myKey': YamlList.wrap([1,2,3], style: CollectionStyle.FLOW),
  'otherKey': [1,2,3], // this just gets default flow...
}, style: CollectionStyle.BLOCK));

I think the criteria to judge this by is based on convenience and utility. Most of the use cases I can see for this might be in modifying configuration files, so I'm not too sure how much value allowing fully flexible might provide

I think this is a fair argument.. Maybe we should only offer is styling through Yaml(Map|List|Scalar).wrap(value, style: ...), and if input is not an YamlNode or if it has ANY style, we just use: