diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d7912f..8e670da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Add support for `MethodSignature` on interface ([GH-28](https://github.com/glutinum-org/cli/issues/28])) * Ignore `ExportAssignment` as we don't know what to do with it yet +* Add support for literal type alias ([GH-45](https://github.com/glutinum-org/cli/issues/45)) + + ```ts + type Mode = "auto"; + type Rank1 = 1; + type Trusty = true; + type Falsy = false; + type PiValue = 3.14; + ``` ## 0.4.0 - 2024-01-08 diff --git a/src/Glutinum.Converter/FsharpAST.fs b/src/Glutinum.Converter/FsharpAST.fs index 2225c78..29ee07c 100644 --- a/src/Glutinum.Converter/FsharpAST.fs +++ b/src/Glutinum.Converter/FsharpAST.fs @@ -217,6 +217,15 @@ type FSharpTypeParameter = Default: FSharpType option } + static member Create + (name: string, ?constraint_: FSharpType, ?default_: FSharpType) + = + { + Name = name + Constraint = constraint_ + Default = default_ + } + type FSharpTypeAlias = { Name: string diff --git a/src/Glutinum.Converter/Reader/TypeNode.fs b/src/Glutinum.Converter/Reader/TypeNode.fs index 8bc9c4f..f4b480a 100644 --- a/src/Glutinum.Converter/Reader/TypeNode.fs +++ b/src/Glutinum.Converter/Reader/TypeNode.fs @@ -178,6 +178,22 @@ let readTypeNode (reader: TypeScriptReader) (typeNode: Ts.TypeNode) : GlueType = |> GlueType.ClassDeclaration | _ -> GlueType.Primitive GluePrimitive.Any + | Ts.SyntaxKind.LiteralType -> + let literalTypeNode = typeNode :?> Ts.LiteralTypeNode + + let literalExpression = + unbox literalTypeNode.literal + + match tryReadLiteral literalExpression with + | Some literal -> GlueType.Literal literal + | None -> + failwith ( + generateReaderError + "type node - literal type" + $"Could not read literal type" + typeNode + ) + | _ -> failwith ( generateReaderError diff --git a/src/Glutinum.Converter/Transform.fs b/src/Glutinum.Converter/Transform.fs index 7d038e8..3eef005 100644 --- a/src/Glutinum.Converter/Transform.fs +++ b/src/Glutinum.Converter/Transform.fs @@ -459,17 +459,63 @@ module TypeAliasDeclaration = : FSharpUnion) |> FSharpType.Union + let transformLiteral (typeAliasName: string) (literalInfo: GlueLiteral) = + let makeTypeAlias primitiveType = + ({ + Name = typeAliasName + Type = primitiveType |> FSharpType.Primitive + TypeParameters = [] + } + : FSharpTypeAlias) + |> FSharpType.TypeAlias + + // We can use StringEnum to represent the literal + match literalInfo with + | GlueLiteral.String value -> + let case = + let caseName = + value + |> String.removeSingleQuote + |> String.removeDoubleQuote + // |> String.capitalizeFirstLetter + + ({ + Attributes = [] + Name = Naming.sanitizeName caseName + } + : FSharpUnionCase) + + ({ + Attributes = + [ + FSharpAttribute.RequireQualifiedAccess + FSharpAttribute.StringEnum CaseRules.None + ] + Name = typeAliasName + Cases = [ case ] + IsOptional = false + } + : FSharpUnion) + |> FSharpType.Union + + // For others type we will default to a type alias + + | GlueLiteral.Int _ -> makeTypeAlias FSharpPrimitive.Int + | GlueLiteral.Float _ -> makeTypeAlias FSharpPrimitive.Float + | GlueLiteral.Bool _ -> makeTypeAlias FSharpPrimitive.Bool + let private transformTypeParameters (typeParameters: GlueTypeParameter list) : FSharpTypeParameter list = typeParameters |> List.map (fun typeParameter -> - { - Name = Naming.sanitizeName typeParameter.Name - Constraint = typeParameter.Constraint |> Option.map transformType - Default = typeParameter.Default |> Option.map transformType - } + FSharpTypeParameter.Create( + typeParameter.Name, + ?constraint_ = + (typeParameter.Constraint |> Option.map transformType), + ?default_ = (typeParameter.Default |> Option.map transformType) + ) ) let private transformTypeAliasDeclaration @@ -477,6 +523,8 @@ let private transformTypeAliasDeclaration : FSharpType = + let typeAliasName = Naming.sanitizeName glueTypeAliasDeclaration.Name + // TODO: Make the transformation more robust match glueTypeAliasDeclaration.Type with | GlueType.Union(GlueTypeUnion cases) as unionType -> @@ -556,7 +604,7 @@ let private transformTypeAliasDeclaration FSharpAttribute.RequireQualifiedAccess FSharpAttribute.StringEnum CaseRules.None ] - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName Cases = cases IsOptional = false } @@ -580,7 +628,7 @@ let private transformTypeAliasDeclaration |> List.distinct ({ - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName Cases = cases } : FSharpEnum) @@ -590,7 +638,7 @@ let private transformTypeAliasDeclaration // Erased enum cases for improving the user experience else ({ - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName Type = transformType unionType TypeParameters = transformTypeParameters @@ -634,7 +682,7 @@ let private transformTypeAliasDeclaration | _ -> FSharpType.Discard ({ - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName Type = typ TypeParameters = transformTypeParameters glueTypeAliasDeclaration.TypeParameters @@ -642,9 +690,12 @@ let private transformTypeAliasDeclaration : FSharpTypeAlias) |> FSharpType.TypeAlias + | GlueType.Literal literalInfo -> + TypeAliasDeclaration.transformLiteral typeAliasName literalInfo + | GlueType.Primitive primitiveInfo -> ({ - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName Type = transformPrimitive primitiveInfo |> FSharpType.Primitive TypeParameters = transformTypeParameters glueTypeAliasDeclaration.TypeParameters @@ -654,7 +705,7 @@ let private transformTypeAliasDeclaration | GlueType.TypeReference typeReference -> ({ - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName Type = transformType (GlueType.TypeReference typeReference) TypeParameters = transformTypeParameters glueTypeAliasDeclaration.TypeParameters @@ -664,7 +715,7 @@ let private transformTypeAliasDeclaration | GlueType.Array glueType -> ({ - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName Type = transformType (GlueType.Array glueType) TypeParameters = transformTypeParameters glueTypeAliasDeclaration.TypeParameters @@ -679,7 +730,7 @@ let private transformTypeAliasDeclaration let partialInterface = { originalInterface with // Use the alias name instead of the original interface name - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName // Transform all the members to optional Members = originalInterface.Members @@ -699,7 +750,7 @@ let private transformTypeAliasDeclaration | GlueType.FunctionType functionType -> { Attributes = [ FSharpAttribute.AllowNullLiteral ] - Name = Naming.sanitizeName glueTypeAliasDeclaration.Name + Name = typeAliasName TypeParameters = transformTypeParameters glueTypeAliasDeclaration.TypeParameters Members = diff --git a/tests/specs/typeAlias/literal/boolean.d.ts b/tests/specs/typeAlias/literal/boolean.d.ts new file mode 100644 index 0000000..c417dba --- /dev/null +++ b/tests/specs/typeAlias/literal/boolean.d.ts @@ -0,0 +1,3 @@ +type Test2 = true; + +type Test3 = false; diff --git a/tests/specs/typeAlias/literal/boolean.fsx b/tests/specs/typeAlias/literal/boolean.fsx new file mode 100644 index 0000000..73bb7b6 --- /dev/null +++ b/tests/specs/typeAlias/literal/boolean.fsx @@ -0,0 +1,14 @@ +module rec Glutinum + +open Fable.Core +open System + +type Test2 = + bool + +type Test3 = + bool + +(***) +#r "nuget: Fable.Core" +(***) diff --git a/tests/specs/typeAlias/literal/float.d.ts b/tests/specs/typeAlias/literal/float.d.ts new file mode 100644 index 0000000..6abdb58 --- /dev/null +++ b/tests/specs/typeAlias/literal/float.d.ts @@ -0,0 +1 @@ +type Test1 = 1.12 diff --git a/tests/specs/typeAlias/literal/float.fsx b/tests/specs/typeAlias/literal/float.fsx new file mode 100644 index 0000000..f6bd2f5 --- /dev/null +++ b/tests/specs/typeAlias/literal/float.fsx @@ -0,0 +1,11 @@ +module rec Glutinum + +open Fable.Core +open System + +type Test1 = + float + +(***) +#r "nuget: Fable.Core" +(***) diff --git a/tests/specs/typeAlias/literal/int.d.ts b/tests/specs/typeAlias/literal/int.d.ts new file mode 100644 index 0000000..8783d67 --- /dev/null +++ b/tests/specs/typeAlias/literal/int.d.ts @@ -0,0 +1 @@ +type Test = 0 diff --git a/tests/specs/typeAlias/literal/int.fsx b/tests/specs/typeAlias/literal/int.fsx new file mode 100644 index 0000000..d20bdc3 --- /dev/null +++ b/tests/specs/typeAlias/literal/int.fsx @@ -0,0 +1,11 @@ +module rec Glutinum + +open Fable.Core +open System + +type Test = + int + +(***) +#r "nuget: Fable.Core" +(***) diff --git a/tests/specs/typeAlias/literal/string.d.ts b/tests/specs/typeAlias/literal/string.d.ts new file mode 100644 index 0000000..895e1f1 --- /dev/null +++ b/tests/specs/typeAlias/literal/string.d.ts @@ -0,0 +1,2 @@ +type GPUAutoLayoutMode = + "auto"; diff --git a/tests/specs/typeAlias/literal/string.fsx b/tests/specs/typeAlias/literal/string.fsx new file mode 100644 index 0000000..0afc5f2 --- /dev/null +++ b/tests/specs/typeAlias/literal/string.fsx @@ -0,0 +1,13 @@ +module rec Glutinum + +open Fable.Core +open System + +[] +[] +type GPUAutoLayoutMode = + | auto + +(***) +#r "nuget: Fable.Core" +(***)