Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add preliminary support for Mapped Types #122

Closed
wants to merge 9 commits into from
16 changes: 15 additions & 1 deletion src/Glutinum.Converter/GlueAST.fs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,18 @@ type GlueUtilityType =
| Record of GlueRecord
// | ReadOnly of GlueType

type GlueMappedType =
{
TypeParameter: GlueTypeParameter
Type: GlueType option
}

type GlueIndexedAccessType =
{
IndexType: GlueType
ObjectType: GlueType
}

[<RequireQualifiedAccess>]
type GlueType =
| Discard
Expand All @@ -278,7 +290,7 @@ type GlueType =
| Union of GlueTypeUnion
| Literal of GlueLiteral
| KeyOf of GlueType
| IndexedAccessType of GlueType
| IndexedAccessType of GlueIndexedAccessType
| ModuleDeclaration of GlueModuleDeclaration
| ClassDeclaration of GlueClassDeclaration
| TypeReference of GlueTypeReference
Expand All @@ -295,6 +307,7 @@ type GlueType =
| ExportDefault of GlueType
| TemplateLiteral
| UtilityType of GlueUtilityType
| MappedType of GlueMappedType

member this.Name =
match this with
Expand Down Expand Up @@ -340,3 +353,4 @@ type GlueType =
match utilityType with
| GlueUtilityType.Partial _
| GlueUtilityType.Record _ -> "obj"
| MappedType _ -> "anonymous"
MangelMaxime marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 3 additions & 2 deletions src/Glutinum.Converter/Glutinum.Converter.fsproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>0.1.0-alpha-001</Version>
Expand All @@ -12,6 +11,7 @@
<Compile Include="Utils/List.fs" />
<Compile Include="Log.fs" />
<Compile Include="TypeScript.fs" />
<Compile Include="TypeScriptHelpers.fs" />
<Compile Include="GlueAST.fs" />
<Compile Include="Reader/Types.fs" />
<Compile Include="Reader/Utils.fs" />
Expand All @@ -29,6 +29,7 @@
<Compile Include="Reader/TypeOperatorNode.fs" />
<Compile Include="Reader/TypeParameters.fs" />
<Compile Include="Reader/UnionTypeNode.fs" />
<Compile Include="Reader/MappedTypeNode.fs" />
<Compile Include="Reader/VariableStatement.fs" />
<Compile Include="Reader/ExportAssignment.fs" />
<Compile Include="Reader/Documentation.fs" />
Expand All @@ -47,4 +48,4 @@
<PackageReference Include="Fable.Promise" />
<PackageReference Include="Glutinum.Chalk" />
</ItemGroup>
</Project>
</Project>
3 changes: 2 additions & 1 deletion src/Glutinum.Converter/Reader/Declaration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ open Glutinum.Converter.GlueAST
open Glutinum.Converter.Reader.Utils
open Glutinum.Converter.Reader.Types
open TypeScript
open TypeScriptHelpers
open Fable.Core.JsInterop

let readDeclaration
Expand Down Expand Up @@ -179,6 +180,6 @@ let readDeclaration
| _ ->
generateReaderError
"declaration"
$"Unsupported kind %A{declaration.kind}"
$"Unsupported kind {SyntaxKind.name declaration.kind} in {__SOURCE_FILE__}"
declaration
|> failwith
41 changes: 35 additions & 6 deletions src/Glutinum.Converter/Reader/IndexedAccessType.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,59 @@ module Glutinum.Converter.Reader.IndexedAccessType
open Glutinum.Converter.GlueAST
open Glutinum.Converter.Reader.Types
open TypeScript
open TypeScriptHelpers

let readIndexedAccessType
(reader: ITypeScriptReader)
(declaration: Ts.IndexedAccessType)
: GlueType
=

let nodeType = declaration.indexType :?> Ts.TypeNode
let indexType =
let idxNodeType = declaration.indexType :?> Ts.TypeNode

let typ =
match nodeType.kind with
match idxNodeType.kind with
| Ts.SyntaxKind.TypeOperator ->
let typeOperatorNode = declaration.indexType :?> Ts.TypeOperatorNode
reader.ReadTypeOperatorNode typeOperatorNode

| Ts.SyntaxKind.NumberKeyword ->
// failwith "Got number keyword"
let numberKeywordNode = declaration.indexType :?> Ts.KeywordTypeNode
reader.ReadTypeNode(numberKeywordNode)

| unsupported ->
let warning =
Utils.generateReaderError
"readIndexedAccessType"
$"Unsupported node kind {SyntaxKind.name unsupported} in {__SOURCE_FILE__}:{__LINE__}"
idxNodeType

reader.Warnings.Add warning

GlueType.Discard

let objectType =
let objNodeType = declaration.objectType :?> Ts.TypeNode

match objNodeType.kind with
| Ts.SyntaxKind.ParenthesizedType ->
let pType = declaration.objectType :?> Ts.ParenthesizedTypeNode
reader.ReadTypeNode pType

| unsupported ->
let warning =
Utils.generateReaderError
"readIndexedAccessType"
$"Unsupported node kind %A{unsupported}"
nodeType
$"Unsupported node kind {SyntaxKind.name unsupported} in {__SOURCE_FILE__}:{__LINE__}"
objNodeType

reader.Warnings.Add warning

GlueType.Discard

GlueType.IndexedAccessType typ
GlueType.IndexedAccessType
{
IndexType = indexType
ObjectType = objectType
}
24 changes: 24 additions & 0 deletions src/Glutinum.Converter/Reader/MappedTypeNode.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Glutinum.Converter.Reader.MappedTypeNode

open Glutinum.Converter.GlueAST
open Glutinum.Converter.Reader.Types
open TypeScript

let readMappedTypeNode
(reader: ITypeScriptReader)
(mappedTypeNode: Ts.MappedTypeNode)
: GlueType
=

let typParam =
// TODO: Make a single reader.ReadTypeParameter method
reader.ReadTypeParameters(
Some(ResizeArray([ mappedTypeNode.typeParameter ]))
)
|> List.head
MangelMaxime marked this conversation as resolved.
Show resolved Hide resolved

{
TypeParameter = typParam
Type = mappedTypeNode.``type`` |> Option.map reader.ReadNode
}
|> GlueType.MappedType
5 changes: 4 additions & 1 deletion src/Glutinum.Converter/Reader/Node.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Glutinum.Converter.Reader.Node
open Glutinum.Converter.GlueAST
open Glutinum.Converter.Reader.Types
open TypeScript
open TypeScriptHelpers

let readNode (reader: ITypeScriptReader) (node: Ts.Node) : GlueType =
match node.kind with
Expand Down Expand Up @@ -47,11 +48,13 @@ let readNode (reader: ITypeScriptReader) (node: Ts.Node) : GlueType =

| Ts.SyntaxKind.ExportDeclaration -> GlueType.Discard

| Ts.SyntaxKind.BooleanKeyword -> reader.ReadTypeNode(node :?> Ts.TypeNode)

| unsupported ->
let warning =
Utils.generateReaderError
"node"
$"Unsupported node kind %A{unsupported}"
$"Unsupported node kind {SyntaxKind.name unsupported} at {__SOURCE_FILE__}"
node

reader.Warnings.Add warning
Expand Down
3 changes: 2 additions & 1 deletion src/Glutinum.Converter/Reader/Parameters.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Glutinum.Converter.Reader.Parameters
open Glutinum.Converter.GlueAST
open Glutinum.Converter.Reader.Types
open TypeScript
open TypeScriptHelpers

let readParameters
(reader: ITypeScriptReader)
Expand All @@ -23,7 +24,7 @@ let readParameters
| _ ->
Utils.generateReaderError
"name"
$"Unsupported kind %A{nameNode.kind}"
$"Unsupported kind {SyntaxKind.name nameNode.kind} in {__SOURCE_FILE__}"
nameNode
|> reader.Warnings.Add

Expand Down
4 changes: 4 additions & 0 deletions src/Glutinum.Converter/Reader/TypeAliasDeclaration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ let readTypeAliasDeclaration
let declaration = declaration.``type`` :?> Ts.IndexedAccessType
reader.ReadIndexedAccessType declaration

| Ts.SyntaxKind.MappedType ->
let mappedTypeNode = declaration.``type`` :?> Ts.MappedTypeNode
reader.ReadMappedTypeNode mappedTypeNode

| _ -> reader.ReadTypeNode declaration.``type``

{
Expand Down
39 changes: 31 additions & 8 deletions src/Glutinum.Converter/Reader/TypeNode.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Glutinum.Converter.Reader.TypeNode
open Glutinum.Converter.GlueAST
open Glutinum.Converter.Reader.Types
open TypeScript
open TypeScriptHelpers
open Fable.Core.JsInterop
open Fable.Core.JS
open Glutinum.Converter.Reader.Utils
Expand Down Expand Up @@ -37,6 +38,7 @@ let private readTypeUsingFlags (reader: ITypeScriptReader) (typ: Ts.Type) =
| _ -> reader.ReadNode declaration

| None -> GlueType.Primitive GluePrimitive.Any

| HasTypeFlags Ts.TypeFlags.String ->
GlueType.Primitive GluePrimitive.String
| HasTypeFlags Ts.TypeFlags.Number ->
Expand Down Expand Up @@ -100,15 +102,14 @@ module UtilityType =
if aliasTypeArguments.Count <> 1 then
GlueType.Discard
else
let symbol = aliasTypeArguments.[0].symbol
let symbol = aliasTypeArguments.[0].getSymbol ()

if isNull symbol || symbol.members.IsNone then
GlueType.Unknown
else
match symbol |> Option.bind _.members with
| None -> GlueType.Unknown
| Some members ->

// Take any of the members
let (_, refMember) =
symbol.members.Value.entries () |> Seq.head
let (_, refMember) = members.entries () |> Seq.head

let originalType = refMember.declarations.Value[0].parent

Expand Down Expand Up @@ -223,7 +224,25 @@ let readTypeNode

let typ = checker.getTypeAtLocation !!typeNodeQuery.exprName

readTypeUsingFlags reader typ
// This is safe as both cases have a `kind` field
let exprNameKind: Ts.SyntaxKind = typeNodeQuery.exprName?kind
// This logic is highly overlapping with readTypeUsingFlags
// It should be refactored to achieve a sane flow
match typ.flags, typ.getSymbol (), exprNameKind with
| HasTypeFlags Ts.TypeFlags.Object, None, Ts.SyntaxKind.Identifier ->
let exprName: Ts.Identifier = !!typeNodeQuery.exprName

let aliasSymbol = checker.getSymbolAtLocation(exprName).Value

let typNode: Ts.TypeNode =
aliasSymbol.declarations.Value[0]?``type``

match typNode.kind with
| Ts.SyntaxKind.TypeOperator ->
reader.ReadTypeOperatorNode(unbox typNode)
| _ -> readTypeUsingFlags reader typ

| _ -> readTypeUsingFlags reader typ

| Ts.SyntaxKind.LiteralType ->
let literalTypeNode = typeNode :?> Ts.LiteralTypeNode
Expand Down Expand Up @@ -392,10 +411,14 @@ let readTypeNode

| Ts.SyntaxKind.TemplateLiteralType -> GlueType.TemplateLiteral

| Ts.SyntaxKind.IndexedAccessType ->
let indexedAccessType = typeNode :?> Ts.IndexedAccessType
reader.ReadIndexedAccessType indexedAccessType

| _ ->
generateReaderError
"type node"
$"Unsupported kind %A{typeNode.kind}"
$"Unsupported kind {SyntaxKind.name typeNode.kind} in {__SOURCE_FILE__}"
typeNode
|> reader.Warnings.Add

Expand Down
7 changes: 7 additions & 0 deletions src/Glutinum.Converter/Reader/TypeScriptReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open Glutinum.Converter.Reader.EnumDeclaration
open Glutinum.Converter.Reader.FunctionDeclaration
open Glutinum.Converter.Reader.IndexedAccessType
open Glutinum.Converter.Reader.InterfaceDeclaration
open Glutinum.Converter.Reader.MappedTypeNode
open Glutinum.Converter.Reader.ModuleDeclaration
open Glutinum.Converter.Reader.Declaration
open Glutinum.Converter.Reader.Node
Expand Down Expand Up @@ -146,3 +147,9 @@ type TypeScriptReader(checker: Ts.TypeChecker) =
: GlueType
=
readNamedTupleMember this namedTupleMember

member this.ReadMappedTypeNode
(declaration: Ts.MappedTypeNode)
: GlueType
=
readMappedTypeNode this declaration
2 changes: 2 additions & 0 deletions src/Glutinum.Converter/Reader/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ type ITypeScriptReader =
abstract ReadIndexedAccessType:
declaration: Ts.IndexedAccessType -> GlueType

abstract ReadMappedTypeNode: declaration: Ts.MappedTypeNode -> GlueType

abstract ReadTypeParameters:
typeParametersOpt: ResizeArray<Ts.TypeParameterDeclaration> option ->
GlueTypeParameter list
Expand Down
Loading
Loading