Skip to content

Commit

Permalink
dotnet fake build -t Format
Browse files Browse the repository at this point in the history
  • Loading branch information
mlaily committed Jun 26, 2022
1 parent 66ae130 commit dec20d7
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 53 deletions.
36 changes: 25 additions & 11 deletions src/CommonRuntime/StructuralInference.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ let asOption =
function
| true, x -> Some x
| false, _ -> None

/// <exclude />
module internal List =
/// Merge two sequences by pairing elements for which
Expand Down Expand Up @@ -228,7 +228,11 @@ let rec subtypeInfered allowEmptyValues ot1 ot2 =
map |> Map.ofList, containsOptional || o1 || o2
)
| InferedType.Collection (o1, t1), InferedType.Collection (o2, t2) ->
InferedType.Collection(unionCollectionOrder o1 o2, unionCollectionTypes allowEmptyValues t1 t2 |> Map.ofList)
InferedType.Collection(
unionCollectionOrder o1 o2,
unionCollectionTypes allowEmptyValues t1 t2
|> Map.ofList
)

// Top type can be merged with anything else
| t, InferedType.Top
Expand All @@ -255,14 +259,15 @@ let rec subtypeInfered allowEmptyValues ot1 ot2 =
| InferedType.Primitive (_, _, _, true) ->
let primitiveOverrides, nonPrimitives =
let primitiveOverrides, nonPrimitives = ResizeArray(), ResizeArray()

tagMerged
|> List.iter (fun (tag, typ) ->
match typ with
| InferedType.Primitive (_, _, _, true) -> primitiveOverrides.Add(tag, typ)
| InferedType.Primitive (_, _, _, false) -> () // We don't need to track normal primitives
| _ -> nonPrimitives.Add(tag, typ))
primitiveOverrides |> List.ofSeq,
nonPrimitives |> List.ofSeq

primitiveOverrides |> List.ofSeq, nonPrimitives |> List.ofSeq

// For all the following cases, if there is at least one overriding primitive,
// normal primitives are discarded.
Expand Down Expand Up @@ -511,7 +516,13 @@ module private Helpers =
/// with the desiredUnit applied,
/// or a value parsed from an inline schema.
/// (For inline schemas, the unit parsed from the schema takes precedence over desiredUnit when present)
let inferPrimitiveType (unitsOfMeasureProvider: IUnitsOfMeasureProvider) (inferenceMode: InferenceMode') (cultureInfo: CultureInfo) (value: string) (desiredUnit: Type option) =
let inferPrimitiveType
(unitsOfMeasureProvider: IUnitsOfMeasureProvider)
(inferenceMode: InferenceMode')
(cultureInfo: CultureInfo)
(value: string)
(desiredUnit: Type option)
=

// Helper for calling TextConversions.AsXyz functions
let (|Parse|_|) func value = func cultureInfo value
Expand Down Expand Up @@ -541,7 +552,9 @@ let inferPrimitiveType (unitsOfMeasureProvider: IUnitsOfMeasureProvider) (infere
>= 0)

let matchValue value =
let makePrimitive typ = Some (InferedType.Primitive(typ, desiredUnit, false, false))
let makePrimitive typ =
Some(InferedType.Primitive(typ, desiredUnit, false, false))

match value with
| "" -> Some InferedType.Null
| Parse TextConversions.AsInteger 0 -> makePrimitive typeof<Bit0>
Expand All @@ -565,14 +578,15 @@ let inferPrimitiveType (unitsOfMeasureProvider: IUnitsOfMeasureProvider) (infere
| nonEmptyValue ->
// Validates that it looks like an inline schema before trying to extract the type and unit:
let m = validInlineSchema.Value.Match(nonEmptyValue)

match m.Success with
| false -> None
| true ->
let typ, unit = parseTypeAndUnit unitsOfMeasureProvider nameToType m.Groups.["typeDefinition"].Value
let unit =
if unit.IsNone
then desiredUnit
else unit
let typ, unit =
parseTypeAndUnit unitsOfMeasureProvider nameToType m.Groups.["typeDefinition"].Value

let unit = if unit.IsNone then desiredUnit else unit

match typ, unit with
| None, _ -> None
| Some (typ, typeWrapper), unit ->
Expand Down
65 changes: 41 additions & 24 deletions src/Csv/CsvInference.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,26 @@ open FSharp.Data.Runtime.StructuralInference
/// This table specifies the mapping from (the names that users can use) to (the types used).
/// The table here for the CsvProvider extends the mapping used for inline schemas by adding nullable and optionals.
let private nameToTypeForCsv =
[ for KeyValue(k, v) in StructuralInference.nameToType -> k, v ]
@
[ "int?", (typeof<int>, TypeWrapper.Nullable)
"int64?", (typeof<int64>, TypeWrapper.Nullable)
"bool?", (typeof<bool>, TypeWrapper.Nullable)
"float?", (typeof<float>, TypeWrapper.Nullable)
"decimal?", (typeof<decimal>, TypeWrapper.Nullable)
"date?", (typeof<DateTime>, TypeWrapper.Nullable)
"datetimeoffset?", (typeof<DateTimeOffset>, TypeWrapper.Nullable)
"timespan?", (typeof<TimeSpan>, TypeWrapper.Nullable)
"guid?", (typeof<Guid>, TypeWrapper.Nullable)
"int option", (typeof<int>, TypeWrapper.Option)
"int64 option", (typeof<int64>, TypeWrapper.Option)
"bool option", (typeof<bool>, TypeWrapper.Option)
"float option", (typeof<float>, TypeWrapper.Option)
"decimal option", (typeof<decimal>, TypeWrapper.Option)
"date option", (typeof<DateTime>, TypeWrapper.Option)
"datetimeoffset option", (typeof<DateTimeOffset>, TypeWrapper.Option)
"timespan option", (typeof<TimeSpan>, TypeWrapper.Option)
"guid option", (typeof<Guid>, TypeWrapper.Option)
"string option", (typeof<string>, TypeWrapper.Option) ]
[ for KeyValue (k, v) in StructuralInference.nameToType -> k, v ]
@ [ "int?", (typeof<int>, TypeWrapper.Nullable)
"int64?", (typeof<int64>, TypeWrapper.Nullable)
"bool?", (typeof<bool>, TypeWrapper.Nullable)
"float?", (typeof<float>, TypeWrapper.Nullable)
"decimal?", (typeof<decimal>, TypeWrapper.Nullable)
"date?", (typeof<DateTime>, TypeWrapper.Nullable)
"datetimeoffset?", (typeof<DateTimeOffset>, TypeWrapper.Nullable)
"timespan?", (typeof<TimeSpan>, TypeWrapper.Nullable)
"guid?", (typeof<Guid>, TypeWrapper.Nullable)
"int option", (typeof<int>, TypeWrapper.Option)
"int64 option", (typeof<int64>, TypeWrapper.Option)
"bool option", (typeof<bool>, TypeWrapper.Option)
"float option", (typeof<float>, TypeWrapper.Option)
"decimal option", (typeof<decimal>, TypeWrapper.Option)
"date option", (typeof<DateTime>, TypeWrapper.Option)
"datetimeoffset option", (typeof<DateTimeOffset>, TypeWrapper.Option)
"timespan option", (typeof<TimeSpan>, TypeWrapper.Option)
"guid option", (typeof<Guid>, TypeWrapper.Option)
"string option", (typeof<string>, TypeWrapper.Option) ]
|> dict

let private nameAndTypeRegex =
Expand All @@ -60,7 +59,9 @@ type private SchemaParseResult =
/// (if we succeed we override the inferred schema, otherwise, we just
/// override the header name)
let private parseSchemaItem unitsOfMeasureProvider str forSchemaOverride =
let parseTypeAndUnit = StructuralInference.parseTypeAndUnit unitsOfMeasureProvider nameToTypeForCsv
let parseTypeAndUnit =
StructuralInference.parseTypeAndUnit unitsOfMeasureProvider nameToTypeForCsv

let name, typ, unit, isOverrideByName, originalName =
let m = overrideByNameRegex.Value.Match str

Expand Down Expand Up @@ -108,7 +109,15 @@ let private parseSchemaItem unitsOfMeasureProvider str forSchemaOverride =
| None, Some _ when forSchemaOverride -> SchemaParseResult.Name str
| None, Some unit -> SchemaParseResult.NameAndUnit(name, unit)

let internal inferCellType unitsOfMeasureProvider preferOptionals missingValues inferenceMode cultureInfo unit (value: string) =
let internal inferCellType
unitsOfMeasureProvider
preferOptionals
missingValues
inferenceMode
cultureInfo
unit
(value: string)
=
// Explicit missing values (NaN, NA, Empty string etc.) will be treated as float unless the preferOptionals is set to true
if Array.exists (value.Trim() |> (=)) missingValues then
if preferOptionals then
Expand Down Expand Up @@ -276,7 +285,15 @@ let internal inferType
let typ =
match schema with
| Some _ -> InferedType.Null // this will be ignored, so just return anything
| None -> inferCellType unitsOfMeasureProvider preferOptionals missingValues inferenceMode cultureInfo unit value
| None ->
inferCellType
unitsOfMeasureProvider
preferOptionals
missingValues
inferenceMode
cultureInfo
unit
value

{ Name = name; Type = typ } ]

Expand Down
7 changes: 6 additions & 1 deletion src/Html/HtmlInference.fs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ let inferListType parameters (values: string[]) =
else
InferedType.Primitive(typeof<float>, None, false, false)
else
getInferedTypeFromString parameters.UnitsOfMeasureProvider parameters.InferenceMode parameters.CultureInfo value None
getInferedTypeFromString
parameters.UnitsOfMeasureProvider
parameters.InferenceMode
parameters.CultureInfo
value
None

values
|> Array.map inferedtype
Expand Down
1 change: 1 addition & 0 deletions src/Json/JsonConversionsGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type JsonConversionCallingType =
/// an expression of other type - the type is specified by `field`
let convertJsonValue missingValuesStr cultureStr canPassAllConversionCallingTypes (field: PrimitiveInferedValue) =


let returnType =
match field.TypeWrapper with
| TypeWrapper.None -> field.TypeWithMeasure
Expand Down
39 changes: 35 additions & 4 deletions src/Json/JsonGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,44 @@ type internal JsonGenerationContext =
InferenceMode: InferenceMode'
UnitsOfMeasureProvider: IUnitsOfMeasureProvider }

static member Create(cultureStr, tpType, unitsOfMeasureProvider, inferenceMode, ?uniqueNiceName, ?typeCache, ?preferDictionaries) =
static member Create
(
cultureStr,
tpType,
unitsOfMeasureProvider,
inferenceMode,
?uniqueNiceName,
?typeCache,
?preferDictionaries
) =
let uniqueNiceName =
defaultArg uniqueNiceName (NameUtils.uniqueGenerator NameUtils.nicePascalName)

let typeCache = defaultArg typeCache (Dictionary())
let preferDictionaries = defaultArg preferDictionaries false
JsonGenerationContext.Create(cultureStr, tpType, uniqueNiceName, typeCache, preferDictionaries, true, inferenceMode, unitsOfMeasureProvider)

static member Create(cultureStr, tpType, uniqueNiceName, typeCache, preferDictionaries, generateConstructors, inferenceMode, unitsOfMeasureProvider) =
JsonGenerationContext.Create(
cultureStr,
tpType,
uniqueNiceName,
typeCache,
preferDictionaries,
true,
inferenceMode,
unitsOfMeasureProvider
)

static member Create
(
cultureStr,
tpType,
uniqueNiceName,
typeCache,
preferDictionaries,
generateConstructors,
inferenceMode,
unitsOfMeasureProvider
) =
{ CultureStr = cultureStr
TypeProviderType = tpType
UniqueNiceName = uniqueNiceName
Expand Down Expand Up @@ -103,7 +132,9 @@ module JsonTypeBuilder =
Type = normalize false inferedType })
// optional only affects the parent, so at top level always set to true regardless of the actual value
InferedType.Record(None, props, optional || topLevel)
| InferedType.Primitive (typ, unit, optional, shouldOverrideOnMerge) when typ = typeof<Bit0> || typ = typeof<Bit1> ->
| InferedType.Primitive (typ, unit, optional, shouldOverrideOnMerge) when
typ = typeof<Bit0> || typ = typeof<Bit1>
->
InferedType.Primitive(typeof<int>, unit, optional, shouldOverrideOnMerge)
| InferedType.Primitive (typ, unit, optional, shouldOverrideOnMerge) when typ = typeof<Bit> ->
InferedType.Primitive(typeof<bool>, unit, optional, shouldOverrideOnMerge)
Expand Down
13 changes: 11 additions & 2 deletions src/Json/JsonProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ type public JsonProvider(cfg: TypeProviderConfig) as this =

let ctx =
JsonGenerationContext.Create(
cultureStr, tpType, unitsOfMeasureProvider, inferenceMode, ?preferDictionaries = Some preferDictionaries)
cultureStr,
tpType,
unitsOfMeasureProvider,
inferenceMode,
?preferDictionaries = Some preferDictionaries
)

let result = JsonTypeBuilder.generateJsonType ctx false false rootName inferedType

Expand All @@ -112,7 +117,11 @@ type public JsonProvider(cfg: TypeProviderConfig) as this =
ProvidedStaticParameter("EmbeddedResource", typeof<string>, parameterDefaultValue = "")
ProvidedStaticParameter("InferTypesFromValues", typeof<bool>, parameterDefaultValue = true)
ProvidedStaticParameter("PreferDictionaries", typeof<bool>, parameterDefaultValue = false)
ProvidedStaticParameter("InferenceMode", typeof<InferenceMode>, parameterDefaultValue = InferenceMode.BackwardCompatible) ]
ProvidedStaticParameter(
"InferenceMode",
typeof<InferenceMode>,
parameterDefaultValue = InferenceMode.BackwardCompatible
) ]

let helpText =
"""<summary>Typed representation of a JSON document.</summary>
Expand Down
8 changes: 7 additions & 1 deletion src/Xml/XmlGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,13 @@ module internal XmlTypeBuilder =

let ctx =
JsonGenerationContext.Create(
cultureStr, ctx.ProvidedType, ctx.UnitsOfMeasureProvider, ctx.InferenceMode, ctx.UniqueNiceName, ctx.JsonTypeCache)
cultureStr,
ctx.ProvidedType,
ctx.UnitsOfMeasureProvider,
ctx.InferenceMode,
ctx.UniqueNiceName,
ctx.JsonTypeCache
)

let result = JsonTypeBuilder.generateJsonType ctx false true "" typ

Expand Down
23 changes: 16 additions & 7 deletions src/Xml/XmlInference.fs
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,30 @@ let private getAttributes unitsOfMeasureProvider inferenceMode cultureInfo (elem
Type = getInferedTypeFromString unitsOfMeasureProvider inferenceMode cultureInfo attr.Value None } ]

let getInferedTypeFromValue unitsOfMeasureProvider inferenceMode cultureInfo (element: XElement) =
let typ = getInferedTypeFromString unitsOfMeasureProvider inferenceMode cultureInfo (element.Value) None
let typ =
getInferedTypeFromString unitsOfMeasureProvider inferenceMode cultureInfo (element.Value) None

match inferenceMode with
// Embedded json is not parsed when InferenceMode is NoInference
| InferenceMode'.NoInference -> typ
|_ ->
| _ ->
match typ with
| InferedType.Primitive (t, _, optional, _) when
t = typeof<string>
&& let v = (element.Value).TrimStart() in
v.StartsWith "{" || v.StartsWith "["
v.StartsWith "{" || v.StartsWith "["
->
try
match JsonValue.Parse (element.Value) with
match JsonValue.Parse(element.Value) with
| (JsonValue.Record _
| JsonValue.Array _) as json ->
let jsonType =
json
|> JsonInference.inferType unitsOfMeasureProvider inferenceMode cultureInfo element.Name.LocalName
|> JsonInference.inferType
unitsOfMeasureProvider
inferenceMode
cultureInfo
element.Name.LocalName

InferedType.Json(jsonType, optional)
| _ -> typ
Expand Down Expand Up @@ -145,13 +150,17 @@ let rec inferLocalType unitsOfMeasureProvider inferenceMode cultureInfo allowEmp
let collection =
inferCollectionType
allowEmptyValues
(Seq.map (inferLocalType unitsOfMeasureProvider inferenceMode cultureInfo allowEmptyValues) children)
(Seq.map
(inferLocalType unitsOfMeasureProvider inferenceMode cultureInfo allowEmptyValues)
children)

yield { Name = ""; Type = collection }

// If it has value, add primitive content
elif not (String.IsNullOrEmpty element.Value) then
let primitive = getInferedTypeFromValue unitsOfMeasureProvider inferenceMode cultureInfo element
let primitive =
getInferedTypeFromValue unitsOfMeasureProvider inferenceMode cultureInfo element

yield { Name = ""; Type = primitive } ]

InferedType.Record(Some(element.Name.ToString()), props, false)
Expand Down
Loading

0 comments on commit dec20d7

Please sign in to comment.