You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Strings that YAML 1.1 reads as booleans or numbers are written unquoted ("NO" → NO, which Jekyll/PyYAML read as false; "12:30" → 750) #188
The serializer in Frontmatter/YamlSerializer.cs:36-40 is built with .WithQuotingNecessaryStrings() and no argument. That quotes only strings that are ambiguous under the YAML 1.2 core schema (true, null, 1.0, 007, and so on). It does not quote strings that are booleans or numbers under YAML 1.1:
yes, no, on, off, y, n, in any case
sexagesimal values such as 12:30
1_000
0b101
Every write path goes through this serializer: CombineFrontmatter (Frontmatter.cs:113), AddFrontmatter (:200), ReplaceFrontmatter (:222) and SerializeFrontmatter (:265). A string value with one of these spellings therefore comes out as a bare scalar.
#137 set out to keep strings from changing type for "Jekyll, Hugo, Astro, js-yaml, PyYAML". Jekyll (Ruby Psych) and PyYAML are YAML 1.1 parsers, so these values still change type for them.
All seven values come back unquoted: k0: yes, k1: No, k2: on, k3: OFF, k6: 12:30, k8: 1_000, k9: 0b101. In the same run, strings that are ambiguous under YAML 1.2 ("01234", "1e3", "TRUE", "0x1F", ".inf", "~") do stay quoted.
How YAML 1.1 consumers read that output:
Value written
PyYAML safe_load
Ruby Psych / Jekyll YAML.load
yes
True
true
No
False
not checked
NO
False
false
on
True
not checked
OFF
False
not checked
12:30
750
45000
1_000
1000
1000
0b101
5
not checked
Why it matters
Static-site generators and scripts consume the frontmatter this library writes. A caller who writes the string "NO" (a country code), "yes" or "no" (an answer field), or "1:30" (a duration) gets a boolean or an integer downstream. This is the "Norway problem". A formatting pass also silently changes the type of values whose authors quoted them specifically to prevent this.
Suggested fix / acceptance criteria
Build the serializer with .WithQuotingNecessaryStrings(quoteYaml1_1Strings: true). YamlDotNet 18.1.0 has this overload. With it, the output is a: "yes", b: "NO", c: "12:30", d: "1_000", e: "0b101", while the bool true and the string hello stay bare.
Watch the interaction with the read path. WithAttemptingUnquotedStringTypeDeserialization reads a plainpublished: yes as the string "yes". With the flag on, that value would be rewritten as published: "yes", which changes its meaning for YAML 1.1 readers in the opposite direction.
Priority: High. Values silently change type for Jekyll and PyYAML consumers (the "Norway problem"), and a formatting pass strips quotes that authors added on purpose.
What's wrong
The serializer in
Frontmatter/YamlSerializer.cs:36-40is built with.WithQuotingNecessaryStrings()and no argument. That quotes only strings that are ambiguous under the YAML 1.2 core schema (true,null,1.0,007, and so on). It does not quote strings that are booleans or numbers under YAML 1.1:yes,no,on,off,y,n, in any case12:301_0000b101Every write path goes through this serializer:
CombineFrontmatter(Frontmatter.cs:113),AddFrontmatter(:200),ReplaceFrontmatter(:222) andSerializeFrontmatter(:265). A string value with one of these spellings therefore comes out as a bare scalar.#137 set out to keep strings from changing type for "Jekyll, Hugo, Astro, js-yaml, PyYAML". Jekyll (Ruby Psych) and PyYAML are YAML 1.1 parsers, so these values still change type for them.
Reproduction (at 23c87b1)
Caller-supplied values:
Round trip of values that were quoted in the source:
All seven values come back unquoted:
k0: yes,k1: No,k2: on,k3: OFF,k6: 12:30,k8: 1_000,k9: 0b101. In the same run, strings that are ambiguous under YAML 1.2 ("01234","1e3","TRUE","0x1F",".inf","~") do stay quoted.How YAML 1.1 consumers read that output:
safe_loadYAML.loadyesTruetrueNoFalseNOFalsefalseonTrueOFFFalse12:30750450001_000100010000b1015Why it matters
Static-site generators and scripts consume the frontmatter this library writes. A caller who writes the string
"NO"(a country code),"yes"or"no"(an answer field), or"1:30"(a duration) gets a boolean or an integer downstream. This is the "Norway problem". A formatting pass also silently changes the type of values whose authors quoted them specifically to prevent this.Suggested fix / acceptance criteria
.WithQuotingNecessaryStrings(quoteYaml1_1Strings: true). YamlDotNet 18.1.0 has this overload. With it, the output isa: "yes",b: "NO",c: "12:30",d: "1_000",e: "0b101", while the booltrueand the stringhellostay bare.WithAttemptingUnquotedStringTypeDeserializationreads a plainpublished: yesas the string"yes". With the flag on, that value would be rewritten aspublished: "yes", which changes its meaning for YAML 1.1 readers in the opposite direction.Serializer. Either land the flag with or after Redesign CombineFrontmatter name matching, merging and YAML rewriting (fixes #175 #176 #177 #178 #162 #167 #154 #150 #151 #153 #161) #180 step 1, or apply it only on the caller-value path.AddFrontmatterwith the string values"NO","yes","on","Off","y","12:30","1_000"and"0b101"writes each one quoted.CombineFrontmatter(AsIs, AsIs, None)keeps them quoted.draft: falsestays a bare boolean.ScalarTypeRoundTripTestsstill pass.Related: #137 (closed; covered the YAML 1.2 cases), #180 (open; preserving document scalar style).