Skip to content

Commit

Permalink
Add support for Partial utility type
Browse files Browse the repository at this point in the history
  • Loading branch information
MangelMaxime committed Dec 2, 2023
1 parent 99e5458 commit e471620
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 28 deletions.
24 changes: 9 additions & 15 deletions src/Glutinum.Converter/GlueAST.fs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ type GlueFunctionDeclaration =
Parameters: GlueParameter list
}

type GlueTypeModuleDeclaration =
type GlueModuleDeclaration =
{
Name: string
IsNamespace: bool
Expand All @@ -127,14 +127,14 @@ type GlueTypeModuleDeclaration =

type GlueConstructor = | GlueConstructor of GlueParameter list

type GlueTypeClassDeclaration =
type GlueClassDeclaration =
{
Name: string
Constructors: GlueConstructor list
Members: GlueMember list
}

type GlueTypeTypeReference =
type GlueTypeReference =
{
Name: string
FullName: string
Expand All @@ -148,12 +148,6 @@ type ExcludedMember =
| Literal of GlueLiteral
// | Function

type GlueTypeExclude =
{
UnionType : GlueTypeUnion
ExcludedMembers: ExcludedMember list
}

[<RequireQualifiedAccess>]
type GlueType =
| Discard
Expand All @@ -167,11 +161,11 @@ type GlueType =
| Literal of GlueLiteral
| KeyOf of GlueType
| IndexedAccessType of GlueType
| ModuleDeclaration of GlueTypeModuleDeclaration
| ClassDeclaration of GlueTypeClassDeclaration
| TypeReference of GlueTypeTypeReference
| ModuleDeclaration of GlueModuleDeclaration
| ClassDeclaration of GlueClassDeclaration
| TypeReference of GlueTypeReference
| Partial of GlueInterface
| Array of GlueType
| Exclude of GlueTypeExclude

member this.Name =
match this with
Expand Down Expand Up @@ -199,5 +193,5 @@ type GlueType =
| Array info -> $"ResizeArray<{info.Name}>"
| IndexedAccessType _
| Union _
| Discard
| Exclude _ -> "obj"
| Partial _
| Discard -> "obj"
11 changes: 10 additions & 1 deletion src/Glutinum.Converter/Printer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,13 @@ let private printInterface (printer: Printer) (interfaceInfo: FSharpInterface) =
if index <> 0 then
printer.WriteInline(" -> ")

printer.WriteInline($"{p.Name}: {printType p.Type}")
let option =
if p.IsOptional then
" option"
else
""

printer.WriteInline($"{p.Name}: {printType p.Type}{option}")
)

if methodInfo.IsStatic then
Expand Down Expand Up @@ -272,6 +278,9 @@ let private printInterface (printer: Printer) (interfaceInfo: FSharpInterface) =
else
printer.WriteInline($": {printType propertyInfo.Type}")

if propertyInfo.IsOptional then
printer.WriteInline(" option")

propertyInfo.Accessor
|> Option.map (
function
Expand Down
62 changes: 53 additions & 9 deletions src/Glutinum.Converter/Read.fs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,53 @@ let private readTypeNode

cases |> GlueTypeUnion |> GlueType.Union

else if fullName = "Partial" then
let typ = checker.getTypeFromTypeNode typeReferenceNode

// Try find the original type
// For now, I am navigating inside of the symbol information
// to find a reference to the interface declaration via one of
// the members of the type
// Is there a better way of doing it?
match typ.aliasTypeArguments with
| None -> GlueType.Discard
| Some aliasTypeArguments ->
if aliasTypeArguments.Count <> 1 then
GlueType.Discard
else
let symbol = aliasTypeArguments.[0].symbol

if symbol.members.IsNone then
GlueType.Discard
else

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

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

match originalType.kind with
| Ts.SyntaxKind.InterfaceDeclaration ->
let interfaceDeclaration =
originalType :?> Ts.InterfaceDeclaration

let members =
interfaceDeclaration.members
|> Seq.toList
|> List.map (tryReadNamedDeclaration checker)

({
Name = interfaceDeclaration.name.getText ()
Members = members
}
: GlueInterface)
|> GlueType.Partial

| _ -> GlueType.Discard

else
({
Name = typeReferenceNode.getText ()
Expand Down Expand Up @@ -498,7 +545,8 @@ let private tryReadNamedDeclaration
Parameters = readParameters checker methodDeclaration.parameters
Type = readTypeNode checker methodDeclaration.``type``
IsOptional = methodDeclaration.questionToken.IsSome
IsStatic = methodDeclaration.modifiers
IsStatic =
methodDeclaration.modifiers
|> Option.map (fun modifiers ->
modifiers
|> Seq.exists (fun modifier ->
Expand Down Expand Up @@ -594,7 +642,7 @@ let private readFunctionDeclaration
let private readModuleDeclaration
(checker: Ts.TypeChecker)
(declaration: Ts.ModuleDeclaration)
: GlueTypeModuleDeclaration
: GlueModuleDeclaration
=

let name = unbox<Ts.Identifier> declaration.name
Expand Down Expand Up @@ -632,14 +680,12 @@ let private readModuleDeclaration
let private readClassDeclaration
(checker: Ts.TypeChecker)
(declaration: Ts.ClassDeclaration)
: GlueTypeClassDeclaration
: GlueClassDeclaration
=

let name = unbox<Ts.Identifier> declaration.name

let members =
declaration.members
|> Seq.toList
let members = declaration.members |> Seq.toList

let constructors, members =
members
Expand All @@ -664,9 +710,7 @@ let private readClassDeclaration
)

let members =
members
|> Seq.toList
|> List.map (tryReadNamedDeclaration checker)
members |> Seq.toList |> List.map (tryReadNamedDeclaration checker)

{
Name = name.getText ()
Expand Down
30 changes: 27 additions & 3 deletions src/Glutinum.Converter/Transform.fs
Original file line number Diff line number Diff line change
Expand Up @@ -579,10 +579,34 @@ let private transformTypeAliasDeclaration
: FSharpTypeAlias)
|> FSharpType.Alias

| GlueType.Partial interfaceInfo ->
let originalInterface = transformInterface interfaceInfo

// Adapt the original interface to make it partial
let partialInterface =
{ originalInterface with
// Use the alias name instead of the original interface name
Name = glueTypeAliasDeclaration.Name
// Transform all the members to optional
Members =
originalInterface.Members
|> List.map (fun m ->
match m with
| FSharpMember.Method method ->
{ method with IsOptional = true }
|> FSharpMember.Method
| FSharpMember.Property property ->
{ property with IsOptional = true }
|> FSharpMember.Property
)
}

FSharpType.Interface partialInterface

| _ -> FSharpType.Discard

let private transformModuleDeclaration
(moduleDeclaration: GlueTypeModuleDeclaration)
(moduleDeclaration: GlueModuleDeclaration)
: FSharpType
=
({
Expand All @@ -594,7 +618,7 @@ let private transformModuleDeclaration
|> FSharpType.Module

let private transformClassDeclaration
(classDeclaration: GlueTypeClassDeclaration)
(classDeclaration: GlueClassDeclaration)
: FSharpType
=
({
Expand Down Expand Up @@ -623,7 +647,7 @@ let rec private transformToFsharp (glueTypes: GlueType list) : FSharpType list =
| GlueType.ClassDeclaration classInfo ->
transformClassDeclaration classInfo

| GlueType.Exclude _
| GlueType.Partial _
| GlueType.Array _
| GlueType.TypeReference _
| GlueType.FunctionDeclaration _
Expand Down
4 changes: 4 additions & 0 deletions tests/Tests.fsproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<!--
This is a temporary file used by Fable to restore dependencies
If you see this file in your project, you can delete it safely
-->
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
6 changes: 6 additions & 0 deletions tests/specs/partial/simple.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
interface Todo {
title: string;
description: string;
}

type TodoPartial = Partial<Todo>;
18 changes: 18 additions & 0 deletions tests/specs/partial/simple.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module rec Glutinum

(***)
#r "nuget: Fable.Core"
(***)

open Fable.Core
open System

[<AllowNullLiteral>]
type Todo =
abstract member title: string with get, set
abstract member description: string with get, set

[<AllowNullLiteral>]
type TodoPartial =
abstract member title: string option with get, set
abstract member description: string option with get, set

0 comments on commit e471620

Please sign in to comment.