From a413d14af55a3946b02fd886b4a46980afab17dd Mon Sep 17 00:00:00 2001 From: Maxime Mangel Date: Tue, 16 Jul 2024 22:53:08 +0200 Subject: [PATCH] fix: if an argument is decorated with `?` and `undefined` or `null` remove the option type [converter][web] Fix #114 --- src/Glutinum.Converter/Transform.fs | 40 ++++++++++++------- ...onParametersDescribedWithOptionalType.d.ts | 5 +++ ...ionParametersDescribedWithOptionalType.fsx | 16 ++++++++ .../optionalArgumentWithOptionalType.d.ts | 3 ++ .../optionalArgumentWithOptionalType.fsx | 19 +++++++++ 5 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 tests/specs/references/class/methodWithOptionParametersDescribedWithOptionalType.d.ts create mode 100644 tests/specs/references/class/methodWithOptionParametersDescribedWithOptionalType.fsx create mode 100644 tests/specs/references/functionDeclaration/optionalArgumentWithOptionalType.d.ts create mode 100644 tests/specs/references/functionDeclaration/optionalArgumentWithOptionalType.fsx diff --git a/src/Glutinum.Converter/Transform.fs b/src/Glutinum.Converter/Transform.fs index 17e51f0..ffeae04 100644 --- a/src/Glutinum.Converter/Transform.fs +++ b/src/Glutinum.Converter/Transform.fs @@ -99,6 +99,22 @@ type TransformContext member _.AddError(error: string) = reporter.Errors.Add error +let private unwrapOptionIfAlreadyOptional + (context: TransformContext) + (typ: GlueType) + (isOptional: bool) + = + // If the property is optional, we want to unwrap the option type + // This is to prevent generating a `string option option` + let typ' = transformType context typ + + if isOptional then + match typ' with + | FSharpType.Option underlyingType -> underlyingType + | _ -> typ' + else + typ' + let private sanitizeNameAndPushScope (name: string) (context: TransformContext) @@ -844,7 +860,11 @@ let private transformParameter let context = context.PushScope(parameter.Name) let typ = - let computedType = transformType context parameter.Type + let computedType = + unwrapOptionIfAlreadyOptional + context + parameter.Type + parameter.IsOptional // In TypeScript, if an argument is marked as spread, users is forced to // use an array. We want to remove the default transformation for that @@ -1010,24 +1030,16 @@ module private TransformMembers = if propertyInfo.IsPrivate && not propertyInfo.IsStatic then None // F# interface can't have private properties else - // If the property is optional, we want to unwrap the option type - // This is to prevent generating a `string option option` - let typ = - let typ' = transformType context propertyInfo.Type - - if propertyInfo.IsOptional then - match typ' with - | FSharpType.Option underlyingType -> underlyingType - | _ -> typ' - else - typ' - { Attributes = [ yield! xmlDocInfo.ObsoleteAttributes ] Name = name OriginalName = propertyInfo.Name Parameters = [] - Type = typ + Type = + unwrapOptionIfAlreadyOptional + context + propertyInfo.Type + propertyInfo.IsOptional TypeParameters = [] IsOptional = propertyInfo.IsOptional IsStatic = propertyInfo.IsStatic diff --git a/tests/specs/references/class/methodWithOptionParametersDescribedWithOptionalType.d.ts b/tests/specs/references/class/methodWithOptionParametersDescribedWithOptionalType.d.ts new file mode 100644 index 0000000..eb54cf8 --- /dev/null +++ b/tests/specs/references/class/methodWithOptionParametersDescribedWithOptionalType.d.ts @@ -0,0 +1,5 @@ +interface PromiseLike { + a(onfulfilled?: string | undefined | null); + b(onfulfilled?: string | undefined); + c(onfulfilled?: string | null); +} diff --git a/tests/specs/references/class/methodWithOptionParametersDescribedWithOptionalType.fsx b/tests/specs/references/class/methodWithOptionParametersDescribedWithOptionalType.fsx new file mode 100644 index 0000000..aaf80a5 --- /dev/null +++ b/tests/specs/references/class/methodWithOptionParametersDescribedWithOptionalType.fsx @@ -0,0 +1,16 @@ +module rec Glutinum + +open Fable.Core +open Fable.Core.JsInterop +open System + +[] +[] +type PromiseLike<'T> = + abstract member a: ?onfulfilled: string -> unit + abstract member b: ?onfulfilled: string -> unit + abstract member c: ?onfulfilled: string -> unit + +(***) +#r "nuget: Fable.Core" +(***) diff --git a/tests/specs/references/functionDeclaration/optionalArgumentWithOptionalType.d.ts b/tests/specs/references/functionDeclaration/optionalArgumentWithOptionalType.d.ts new file mode 100644 index 0000000..f150723 --- /dev/null +++ b/tests/specs/references/functionDeclaration/optionalArgumentWithOptionalType.d.ts @@ -0,0 +1,3 @@ +declare function a(onfulfilled?: string | undefined | null); +declare function b(onfulfilled?: string | undefined); +declare function c(onfulfilled?: string | null); diff --git a/tests/specs/references/functionDeclaration/optionalArgumentWithOptionalType.fsx b/tests/specs/references/functionDeclaration/optionalArgumentWithOptionalType.fsx new file mode 100644 index 0000000..e2e4c98 --- /dev/null +++ b/tests/specs/references/functionDeclaration/optionalArgumentWithOptionalType.fsx @@ -0,0 +1,19 @@ +module rec Glutinum + +open Fable.Core +open Fable.Core.JsInterop +open System + +[] +[] +type Exports = + [] + static member a (?onfulfilled: string) : unit = nativeOnly + [] + static member b (?onfulfilled: string) : unit = nativeOnly + [] + static member c (?onfulfilled: string) : unit = nativeOnly + +(***) +#r "nuget: Fable.Core" +(***)