@@ -18,6 +18,110 @@ open YamlDotNet.RepresentationModel
1818
1919module internal YamlConversions =
2020
21+ // For design-time type inference: quoted YAML scalars should always be typed as
22+ // strings, even when InferTypesFromValues=true. We use a non-numeric sentinel value
23+ // so that JsonInference does not re-infer "01234" as int, etc.
24+ let rec yamlNodeToJsonValueForInference ( node : YamlNode ) : JsonValue =
25+ match node with
26+ | :? YamlMappingNode as mapping ->
27+ let props =
28+ [| for kvp in mapping.Children do
29+ let key =
30+ match kvp.Key with
31+ | :? YamlScalarNode as s -> s.Value
32+ | other -> other.ToString()
33+
34+ yield ( key, yamlNodeToJsonValueForInference kvp.Value) |]
35+
36+ JsonValue.Record props
37+
38+ | :? YamlSequenceNode as sequence ->
39+ let elements =
40+ [| for item in sequence.Children -> yamlNodeToJsonValueForInference item |]
41+
42+ JsonValue.Array elements
43+
44+ | :? YamlScalarNode as scalar ->
45+ let value = scalar.Value
46+
47+ if value = null then
48+ JsonValue.Null
49+ else
50+ match scalar.Style with
51+ | YamlDotNet.Core.ScalarStyle.SingleQuoted
52+ | YamlDotNet.Core.ScalarStyle.DoubleQuoted
53+ | YamlDotNet.Core.ScalarStyle.Literal
54+ | YamlDotNet.Core.ScalarStyle.Folded ->
55+ // Explicitly quoted scalars are always strings in YAML.
56+ // Use the original value if it is clearly non-numeric; otherwise substitute
57+ // a plain-letter sentinel so that value-based type inference sees a string.
58+ let sentinel =
59+ match
60+ System.Decimal.TryParse(
61+ value,
62+ System.Globalization.NumberStyles.Float,
63+ System.Globalization.CultureInfo.InvariantCulture
64+ )
65+ with
66+ | true , _ -> " s"
67+ | false , _ ->
68+ match
69+ System.Double.TryParse(
70+ value,
71+ System.Globalization.NumberStyles.Float,
72+ System.Globalization.CultureInfo.InvariantCulture
73+ )
74+ with
75+ | true , _ -> " s"
76+ | false , _ -> value
77+
78+ JsonValue.String sentinel
79+ | _ ->
80+ // Plain scalars: use the same type-aware conversion as runtime
81+ if value = " null" || value = " ~" || value = " " then
82+ JsonValue.Null
83+ elif value = " true" || value = " True" || value = " TRUE" then
84+ JsonValue.Boolean true
85+ elif value = " false" || value = " False" || value = " FALSE" then
86+ JsonValue.Boolean false
87+ elif value = " .inf" || value = " .Inf" || value = " .INF" || value = " +.inf" then
88+ JsonValue.Float System.Double.PositiveInfinity
89+ elif value = " -.inf" || value = " -.Inf" || value = " -.INF" then
90+ JsonValue.Float System.Double.NegativeInfinity
91+ elif value = " .nan" || value = " .NaN" || value = " .NAN" then
92+ JsonValue.Float System.Double.NaN
93+ else
94+ match
95+ System.Decimal.TryParse(
96+ value,
97+ System.Globalization.NumberStyles.Float,
98+ System.Globalization.CultureInfo.InvariantCulture
99+ )
100+ with
101+ | true , d -> JsonValue.Number d
102+ | false , _ ->
103+ match
104+ System.Double.TryParse(
105+ value,
106+ System.Globalization.NumberStyles.Float,
107+ System.Globalization.CultureInfo.InvariantCulture
108+ )
109+ with
110+ | true , f -> JsonValue.Float f
111+ | false , _ -> JsonValue.String value
112+
113+ | _ -> JsonValue.Null
114+
115+ let parseYamlForInference ( text : string ) : JsonValue =
116+ let yaml = YamlStream()
117+ use reader = new StringReader( text)
118+ yaml.Load( reader)
119+
120+ if yaml.Documents.Count = 0 then
121+ JsonValue.Null
122+ else
123+ yamlNodeToJsonValueForInference yaml.Documents.[ 0 ]. RootNode
124+
21125 let rec yamlNodeToJsonValue ( node : YamlNode ) : JsonValue =
22126 match node with
23127 | :? YamlMappingNode as mapping ->
@@ -189,6 +293,20 @@ type YamlDocument =
189293 IsError = false ) >]
190294 static member ParseToJsonValue ( text : string ) : JsonValue = YamlConversions.parseYaml text
191295
296+ /// <summary >
297+ /// Like ParseToJsonValue but for design-time type inference: explicitly quoted YAML scalars
298+ /// are represented as string sentinels so that InferTypesFromValues does not re-infer
299+ /// "01234" as int, etc.
300+ /// </summary >
301+ /// <exclude />
302+ [<EditorBrowsableAttribute( EditorBrowsableState.Never) >]
303+ [<CompilerMessageAttribute( " This method is intended for use in generated code only." ,
304+ 10001 ,
305+ IsHidden = true ,
306+ IsError = false ) >]
307+ static member ParseToJsonValueForInference ( text : string ) : JsonValue =
308+ YamlConversions.parseYamlForInference text
309+
192310 /// <exclude />
193311 [<EditorBrowsableAttribute( EditorBrowsableState.Never) >]
194312 [<CompilerMessageAttribute( " This method is intended for use in generated code only." ,
0 commit comments