Skip to content

Commit eaf1d84

Browse files
committed
feat: adding an option to control style of strings
1 parent 9536e6b commit eaf1d84

File tree

4 files changed

+81
-1
lines changed

4 files changed

+81
-1
lines changed

README.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,50 @@ parses this metadata, re-applies the tags and styles, and discards the extra pai
103103
4 entries instead of 2. A filter that expects all array entries to be mappings may break due to the presence of string
104104
metadata keys. Check your jq filter for compatibility/semantic validity when using the ``-Y`` option.
105105
106+
Forcing string styles using the ``-z`` (``--yaml-string_styles``) option
107+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108+
The ``-z`` option will assume that strings might start with some style information.
109+
This option is only useful when using YAML-output (using ``-y`` or ``-Y``)
110+
111+
To control the string style, the string itself has to be prepanded by additional information.
112+
Valid control strings are:
113+
114+
* ``__yq_style_'__``: uses single quotes ``'``
115+
* ``__yq_style_"__``: uses double quotes ``"``
116+
* ``__yq_style_>__`` uses ``>``, ``>`` or ``>-``, (depending on if the text has trailing break lines)
117+
* ``__yq_style_|__`` uses ``|``, ``|+`` or ``|-``, (depending on if the text has trailing break lines)
118+
119+
Assume you have some input file ``input.yaml``::
120+
121+
field1: "I am a\nmultiline string"
122+
123+
Example usage::
124+
125+
yq -y -z '.field1 |= "__yq_style_|__" + .' input.yaml
126+
127+
This will output::
128+
129+
field1: |
130+
I am a
131+
multiline string
132+
133+
The usage can be simplified by adding the function ``style`` to ``~/.jq`` and/or to your scripts::
134+
135+
# remove existing styles
136+
def style: if test("^__yq_style_.__") then .[14:] | style else . end;
137+
138+
# set a style
139+
def style(s):
140+
if s | length == 1 then "__yq_style_" + s + "__" + (. | style) # remove previous styles
141+
else error("Only valid symbols are \", ', |, >, _")
142+
end;
143+
144+
145+
This allows to simpify the above example to::
146+
147+
yq -y -z '.field1 |= style("|")' input.yaml
148+
149+
106150
XML support
107151
-----------
108152
``yq`` also supports XML. The ``yq`` package installs an executable, ``xq``, which

yq/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ def yq(
192192
expand_aliases=True,
193193
max_expansion_factor=1024,
194194
yaml_output_grammar_version="1.1",
195+
yaml_string_styles=False,
195196
jq_args=frozenset(),
196197
exit_func=None,
197198
):
@@ -268,6 +269,7 @@ def yq(
268269
use_annotations=use_annotations,
269270
indentless=indentless_lists,
270271
grammar_version=yaml_output_grammar_version,
272+
use_string_styles=yaml_string_styles
271273
)
272274
yaml.dump_all(
273275
decode_docs(jq_out, json_decoder),

yq/dumper.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,27 @@ def ignore_aliases(self, data):
2626
yaml_item_annotation_re = re.compile(r"^__yq_(?P<type>tag|style)_(?P<key>\d+)_(?P<value>.+)__$")
2727

2828

29-
def get_dumper(use_annotations=False, indentless=False, grammar_version="1.1"):
29+
def extractStringStyle(v):
30+
if v.value.startswith("__yq_style_|__"):
31+
v.value = v.value[14:]
32+
v.style = '|'
33+
elif v.value.startswith("__yq_style_>__"):
34+
v.value = v.value[14:]
35+
v.style = '>'
36+
elif v.value.startswith("__yq_style_'__"):
37+
v.value = v.value[14:]
38+
v.style = '\''
39+
elif v.value.startswith("__yq_style_\"__"):
40+
v.value = v.value[14:]
41+
v.style = '"'
42+
elif v.value.startswith("__yq_style____"):
43+
v.value = v.value[14:]
44+
v.style = None
45+
46+
return v
47+
48+
49+
def get_dumper(use_annotations=False, indentless=False, grammar_version="1.1", use_string_styles=False):
3050
# if not (use_annotations or indentless):
3151
# return default_dumper
3252

@@ -55,6 +75,7 @@ def represent_dict(dumper, data):
5575
v.flow_style = True
5676
if hashed_key in custom_tags:
5777
v.tag = custom_tags[hashed_key]
78+
5879
return mapping
5980

6081
def represent_list(dumper, data):
@@ -79,10 +100,17 @@ def represent_list(dumper, data):
79100
v.flow_style = True
80101
if str(i) in custom_tags:
81102
v.tag = custom_tags[str(i)]
103+
82104
return sequence
83105

106+
def represent_str(dumper, data):
107+
scalar = dumper.represent_scalar("tag:yaml.org,2002:str", value=data)
108+
return extractStringStyle(scalar)
109+
84110
dumper = OrderedIndentlessDumper if indentless else OrderedDumper
85111
dumper.add_representer(dict, represent_dict)
86112
dumper.add_representer(list, represent_list)
113+
if use_string_styles:
114+
dumper.add_representer(str, represent_str)
87115
set_yaml_grammar(dumper, grammar_version=grammar_version)
88116
return dumper

yq/parser.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ def get_parser(program_name, description):
100100
parser.add_argument(
101101
"--yaml-output-grammar-version", "--yml-out-ver", choices=["1.1", "1.2"], default="1.1", help=grammar_help
102102
)
103+
parser.add_argument(
104+
"--yaml-string-styles",
105+
"--yml-string-styles",
106+
"-z",
107+
action="store_true",
108+
help="Allows special strings to control style of strings (only valid in combination with -y or -Y)")
103109
parser.add_argument("--width", "-w", type=int, help=width_help)
104110
parser.add_argument("--indentless-lists", "--indentless", action="store_true", help=indentless_help)
105111
parser.add_argument("--explicit-start", action="store_true", help=explicit_start_help)

0 commit comments

Comments
 (0)