diff --git a/README.rst b/README.rst index 6fcdfb9..fb6b841 100644 --- a/README.rst +++ b/README.rst @@ -105,6 +105,49 @@ parses this metadata, re-applies the tags and styles, and discards the extra pai yq does not support passing YAML comments into the JSON representation used by jq, or roundtripping such comments. +Forcing string styles using the ``-z`` (``--yaml-string_styles``) option +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``-z`` option will assume that strings might start with some style information. +This option is only useful when using YAML-output (using ``-y`` or ``-Y``) + +To control the string style, the string itself has to be prepanded by additional information. +Valid control strings are: + +* ``__yq_style_'__``: uses single quotes ``'`` +* ``__yq_style_"__``: uses double quotes ``"`` +* ``__yq_style_>__`` uses ``>``, ``>`` or ``>-``, (depending on if the text has trailing break lines) +* ``__yq_style_|__`` uses ``|``, ``|+`` or ``|-``, (depending on if the text has trailing break lines) + +Assume you have some input file ``input.yaml``:: + + field1: "I am a\nmultiline string" + +Example usage:: + + yq -y -z '.field1 |= "__yq_style_|__" + .' input.yaml + +This will output:: + + field1: | + I am a + multiline string + +The usage can be simplified by adding the function ``style`` to ``~/.jq`` and/or to your scripts:: + + # remove existing styles + def style: if test("^__yq_style_.__") then .[14:] | style else . end; + + # set a style + def style(s): + if s | length == 1 then "__yq_style_" + s + "__" + (. | style) # remove previous styles + else error("Only valid symbols are \", ', |, >, _") + end; + + +This allows to simpify the above example to:: + + yq -y -z '.field1 |= style("|")' input.yaml + XML support ----------- ``yq`` also supports XML. The ``yq`` package installs an executable, ``xq``, which diff --git a/yq/__init__.py b/yq/__init__.py index d95ac4b..182cd5c 100644 --- a/yq/__init__.py +++ b/yq/__init__.py @@ -183,6 +183,7 @@ def yq( expand_aliases=True, max_expansion_factor=1024, yaml_output_grammar_version="1.1", + yaml_string_styles=False, jq_args=frozenset(), exit_func=None, ): @@ -261,6 +262,7 @@ def yq( use_annotations=use_annotations, indentless=indentless_lists, grammar_version=yaml_output_grammar_version, + use_string_styles=yaml_string_styles ) yaml.dump_all( decode_docs(jq_out, json_decoder), diff --git a/yq/dumper.py b/yq/dumper.py index d906d2d..8b27a7a 100644 --- a/yq/dumper.py +++ b/yq/dumper.py @@ -26,7 +26,27 @@ def ignore_aliases(self, data): yaml_item_annotation_re = re.compile(r"^__yq_(?Ptag|style)_(?P\d+)_(?P.+)__$") -def get_dumper(use_annotations=False, indentless=False, grammar_version="1.1"): +def extractStringStyle(v): + if v.value.startswith("__yq_style_|__"): + v.value = v.value[14:] + v.style = '|' + elif v.value.startswith("__yq_style_>__"): + v.value = v.value[14:] + v.style = '>' + elif v.value.startswith("__yq_style_'__"): + v.value = v.value[14:] + v.style = '\'' + elif v.value.startswith("__yq_style_\"__"): + v.value = v.value[14:] + v.style = '"' + elif v.value.startswith("__yq_style____"): + v.value = v.value[14:] + v.style = None + + return v + + +def get_dumper(use_annotations=False, indentless=False, grammar_version="1.1", use_string_styles=False): # if not (use_annotations or indentless): # return default_dumper @@ -55,6 +75,7 @@ def represent_dict(dumper, data): v.flow_style = True if hashed_key in custom_tags: v.tag = custom_tags[hashed_key] + return mapping def represent_list(dumper, data): @@ -79,10 +100,17 @@ def represent_list(dumper, data): v.flow_style = True if str(i) in custom_tags: v.tag = custom_tags[str(i)] + return sequence + def represent_str(dumper, data): + scalar = dumper.represent_scalar("tag:yaml.org,2002:str", value=data) + return extractStringStyle(scalar) + dumper = OrderedIndentlessDumper if indentless else OrderedDumper dumper.add_representer(dict, represent_dict) dumper.add_representer(list, represent_list) + if use_string_styles: + dumper.add_representer(str, represent_str) set_yaml_grammar(dumper, grammar_version=grammar_version) return dumper diff --git a/yq/parser.py b/yq/parser.py index 641edd5..fd43abb 100644 --- a/yq/parser.py +++ b/yq/parser.py @@ -100,6 +100,12 @@ def get_parser(program_name, description): parser.add_argument( "--yaml-output-grammar-version", "--yml-out-ver", choices=["1.1", "1.2"], default="1.1", help=grammar_help ) + parser.add_argument( + "--yaml-string-styles", + "--yml-string-styles", + "-z", + action="store_true", + help="Allows special strings to control style of strings (only valid in combination with -y or -Y)") parser.add_argument("--width", "-w", type=int, help=width_help) parser.add_argument("--indentless-lists", "--indentless", action="store_true", help=indentless_help) parser.add_argument("--explicit-start", action="store_true", help=explicit_start_help)