tools icon indicating copy to clipboard operation
tools copied to clipboard

String value is escaped in an unwanted way

Open Schwusch opened this issue 4 years ago • 4 comments

When updating a string value with forward slashes, the resulting string escapes the forward slashes unnecessarily:

final doc = YamlEditor('exampleKey: \${file(../../bar.yml)}');

doc.update(['exampleKey'], '\${file(../../foo.yml)}');

print(doc);
// exampleKey: ${file(..\/..\/bar.yml)}

My current workaround is to modify the resulting string:

doc.toString().replaceAll('\\/', '/')

It would be nice to customize that behaviour.

Schwusch avatar Feb 28 '22 14:02 Schwusch

// exampleKey: ${file(..\/..\/bar.yml)}

Are you sure it's not double quoting it, as: // exampleKey: "${file(..\/..\/bar.yml)}"


On topic, I'm guessing we could make the strings prettier. Contributions are welcome, but I think it would be best to have:

  • Lots of test cases, and,
  • Source code comments arguing why not escaping certain sequences is always safe.

jonasfj avatar Mar 17 '22 10:03 jonasfj

Are you sure it's not double quoting it, as: // exampleKey: "${file(../../bar.yml)}"

Oh yeah, that's right. When skipping the { and } characters, everything worked as expected during experimentation, with no double quotes or escaping:

doc.update(['exampleKey'], '\$file(../../foo.yml)');
print(doc);
// exampleKey: $file(../../foo.yml)

So curly braces makes this function return true: https://github.com/dart-lang/yaml_edit/blob/4fadb43801b07f90b3f0c6065dbce4efc6d8d55e/lib/src/utils.dart#L15 and then that triggers escaping all code units in this map: https://github.com/dart-lang/yaml_edit/blob/4fadb43801b07f90b3f0c6065dbce4efc6d8d55e/lib/src/strings.dart#L286 But the forward slashes, in itself, does not trigger any character escaping.

I can make a PR if there is a consensus on the solution. Personally, I'd like to pass a parameter to skip all checks for dangerous strings and skip all character replacing somehow.

Schwusch avatar Mar 18 '22 19:03 Schwusch

Image

Hi, back again.

I'm trying to insert the following value in a map:

$ref: "#/components/schemas/fooObject"

using this snippet:

final specEditor = YamlEditor(asyncApiSpecText);
specEditor.update(
  ['some', 'path'],
  {'\$ref': '#/components/schemas/fooObject'},
);

The result is:

some:
  path:
    $ref: "#\/components\/schemas\/fooObject"

Schwusch avatar Jun 09 '25 13:06 Schwusch

Sorry if my comment is overkill. I just wanted to explain YamlEditor`'s logic leading to the escaped forward slashes.

Forward slashes must be escaped in YAML for JSON compatibility when strings are encoded as ScalarStyle.DOUBLE_QUOTED. See section linked

TLDR: YamlEditor is just trying to make sure it remains spec-compliant and package:yaml doesn't complain.


@Schwusch the leading # is not safe in ScalarStyle.PLAIN in YAML because of the preceding whitespace just after :. See here.

Your string would be considered a comment by the parser if inserted with the leading #. It defaults to ScalarStyle.DOUBLE_QUOTED to preserve your leading #.

# Your ref key would be null if parsed
some:
  path:
    $ref: #/components/schemas/fooObject
const asyncApiSpecText = r'''
some:
  path:
    $ref: #/components/schemas/fooObject
''';

print(loadYaml(asyncApiSpecText)); // {some: {path: {$ref: null}}}

If you omit the leading #, the string will be encoded without even being defaulted to ScalarStyle.DOUBLE_QUOTED.

final specEditor = YamlEditor(asyncApiSpecText);
specEditor.update(
  ['some', 'path'],
  {'\$ref': '/components/schemas/fooObject'},
);
some:
  path:
    $ref: /components/schemas/fooObject

kekavc24 avatar Nov 01 '25 15:11 kekavc24