Skip to content

Quote scalars with a leading or trailing tab - #1125

Open
gaoflow wants to merge 1 commit into
aaubry:masterfrom
gaoflow:quote-leading-trailing-tab
Open

Quote scalars with a leading or trailing tab#1125
gaoflow wants to merge 1 commit into
aaubry:masterfrom
gaoflow:quote-leading-trailing-tab

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 28, 2026

Copy link
Copy Markdown

AnalyzeScalar already forces quoting for a scalar with a leading or trailing space, but the whitespace check it uses (buffer.IsSpace()) is space-only, so a leading or trailing tab falls through and the value is emitted as a plain scalar. That output is not self-consistent:

  • on read-back the leading/trailing tab is stripped as indentation, so the string round-trips to the wrong value;
  • when the tab immediately precedes a flow indicator, the parser rejects the emitter's own output with a SemanticErrorException.

Repro on the default serializer:

var ser = new SerializerBuilder().Build();
var deser = new DeserializerBuilder().Build();

// #732 - throws on the emitter's own output:
var y = ser.Serialize(new List<string> { "\t," });   // "- \t,\n"
deser.Deserialize<List<string>>(y);                   // SemanticErrorException

// silent truncation (a leading space is quoted, a tab is not):
deser.Deserialize<string>(ser.Serialize(" x"));       // " x"  (ok, quoted)
deser.Deserialize<string>(ser.Serialize("\tx"));      // "x"   (leading tab lost)
deser.Deserialize<string>(ser.Serialize("x\t"));      // "x"   (trailing tab lost)

This also covers the tab cases from #493 (e.g. a Dictionary value of "\thello").

Note this is the default emitter path, separate from the \s regex in TypeAssigningEventEmitter that #732 was closed against - that fix only applies with .WithQuotingNecessaryStrings(), so the plain default builder above still reproduces.

Fix: use the existing IsWhite() (space or tab) predicate for the leading/trailing whitespace detection, so a tab is treated like a space. The change is limited to leading/trailing detection - an interior tab is safe unquoted and stays plain ("x\ty" still emits as x\ty and round-trips).

Tests in SerializationTests cover leading/trailing/only tab round-trips, the "\t," list no-throw case, and pin that an interior tab stays plain and that leading/trailing spaces are unchanged. Full suite green on net10.0.

The emitter already forces quoting for a leading or trailing space, but the
whitespace check in AnalyzeScalar used a space-only predicate, so a leading
or trailing tab was emitted as a plain scalar. On read-back the tab is
stripped as indentation, or (when it precedes a flow indicator) the parser
rejects the emitter's own output with a SemanticErrorException (aaubry#732, aaubry#493).

Use IsWhite() so a tab is treated like a space for leading/trailing
detection. Interior tabs are unaffected and stay plain.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant