From 7c609653dc65d18a50382ca85183c7a824c243d1 Mon Sep 17 00:00:00 2001 From: Caroline Ott Date: Fri, 18 Oct 2024 20:49:00 +0200 Subject: [PATCH] add optional field to inputs --- src/CWL/Decode.fs | 24 ++++-- src/CWL/Inputs.fs | 5 +- tests/CWL/Inputs.Tests.fs | 16 +++- tests/TestingUtils/TestObjects.CWL/Inputs.fs | 3 + tests/TestingUtils/packages.lock.json | 91 +++++++++++++------- 5 files changed, 99 insertions(+), 40 deletions(-) diff --git a/src/CWL/Decode.fs b/src/CWL/Decode.fs index ea4f8690..9d17d0f2 100644 --- a/src/CWL/Decode.fs +++ b/src/CWL/Decode.fs @@ -90,9 +90,14 @@ module Decode = | _ -> failwith "Invalid CWL type" ) - /// Match the input string to the possible CWL types - let cwlTypeStringMatcher t (get: Decode.IGetters) = - match t with + /// Match the input string to the possible CWL types and checks if it is optional + let cwlTypeStringMatcher (t: string) (get: Decode.IGetters) = + let optional, newT = + if t.EndsWith("?") then + true, t.Replace("?", "") + else + false, t + match newT with | "File" -> File (FileInstance ()) | "Directory" -> Directory (DirectoryInstance ()) | "Dirent" -> (get.Required.Field "listing" direntDecoder) @@ -114,9 +119,10 @@ module Decode = | "stdout" -> Stdout | "null" -> Null | _ -> failwith "Invalid CWL type" + , optional /// Access the type field and decode a YAMLElement into a CWLType - let cwlTypeDecoder: (YAMLiciousTypes.YAMLElement -> CWLType) = + let cwlTypeDecoder: (YAMLiciousTypes.YAMLElement -> CWLType*bool) = Decode.object (fun get -> let cwlType = get.Required.Field @@ -133,7 +139,7 @@ module Decode = cwlTypeStringMatcher t get | None -> let cwlTypeArray = get.Required.Field "type" cwlArrayTypeDecoder - cwlTypeArray + cwlTypeArray, false ) /// Decode a YAMLElement into an Output Array @@ -147,8 +153,8 @@ module Decode = let outputSource = get.Optional.Field "outputSource" Decode.string let cwlType = match value with - | YAMLElement.Object [YAMLElement.Value v] -> cwlTypeStringMatcher v.Value get - | _ -> cwlTypeDecoder value + | YAMLElement.Object [YAMLElement.Value v] -> cwlTypeStringMatcher v.Value get |> fst + | _ -> cwlTypeDecoder value |> fst let output = Output( key, @@ -324,7 +330,7 @@ module Decode = for key in dict.Keys do let value = dict.[key] let inputBinding = inputBindingDecoder value - let cwlType = + let cwlType,optional = match value with | YAMLElement.Object [YAMLElement.Value v] -> cwlTypeStringMatcher v.Value get | _ -> cwlTypeDecoder value @@ -335,6 +341,8 @@ module Decode = ) if inputBinding.IsSome then DynObj.setOptionalProperty "inputBinding" inputBinding input + if optional then + DynObj.setOptionalProperty "optional" (Some true) input input |] |> ResizeArray diff --git a/src/CWL/Inputs.fs b/src/CWL/Inputs.fs index 2b688414..67ee36d1 100644 --- a/src/CWL/Inputs.fs +++ b/src/CWL/Inputs.fs @@ -18,15 +18,18 @@ module Inputs = type Input ( name: string, ?type_: CWLType, - ?inputBinding: InputBinding + ?inputBinding: InputBinding, + ?optional: bool ) as this = inherit DynamicObj () do DynObj.setOptionalProperty ("type") type_ this DynObj.setOptionalProperty ("inputBinding") inputBinding this + DynObj.setOptionalProperty ("optional") optional this member this.Name = name member this.Type_ = DynObj.tryGetTypedPropertyValue ("type") this member this.InputBinding = DynObj.tryGetTypedPropertyValue ("inputBinding") this + member this.Optional = DynObj.tryGetTypedPropertyValue ("optional") this module Workflow = diff --git a/tests/CWL/Inputs.Tests.fs b/tests/CWL/Inputs.Tests.fs index 4176c706..ddf7c545 100644 --- a/tests/CWL/Inputs.Tests.fs +++ b/tests/CWL/Inputs.Tests.fs @@ -14,7 +14,7 @@ let decodeInput = let testInput = testList "Decode" [ - testCase "Length" <| fun _ -> Expect.equal 3 decodeInput.Count "" + testCase "Length" <| fun _ -> Expect.equal 5 decodeInput.Count "" testList "Directory" [ let directoryItem = decodeInput.[0] testCase "Name" <| fun _ -> Expect.equal "arcDirectory" directoryItem.Name "" @@ -26,8 +26,20 @@ let testInput = testCase "Type" <| fun _ -> Expect.equal (File (FileInstance())) fileItem.Type_.Value "" testCase "InputBinding" <| fun _ -> Expect.equal (Some {Position = Some 1; Prefix = Some "--example"; ItemSeparator = None; Separate = None}) fileItem.InputBinding "" ] + testList "File optional" [ + let fileItem = decodeInput.[2] + testCase "Name" <| fun _ -> Expect.equal "argOptional" fileItem.Name "" + testCase "Type" <| fun _ -> Expect.equal (File (FileInstance())) fileItem.Type_.Value "" + testCase "Optional" <| fun _ -> Expect.equal (Some true) fileItem.Optional "" + ] + testList "File array optional" [ + let fileItem = decodeInput.[3] + testCase "Name" <| fun _ -> Expect.equal "argOptionalMap" fileItem.Name "" + testCase "Type" <| fun _ -> Expect.equal (Array (File (FileInstance()))) fileItem.Type_.Value "" + testCase "Optional" <| fun _ -> Expect.equal (Some true) fileItem.Optional "" + ] testList "String" [ - let stringItem = decodeInput.[2] + let stringItem = decodeInput.[4] testCase "Name" <| fun _ -> Expect.equal "secondArg" stringItem.Name "" testCase "Type" <| fun _ -> let expected = String diff --git a/tests/TestingUtils/TestObjects.CWL/Inputs.fs b/tests/TestingUtils/TestObjects.CWL/Inputs.fs index 34024a3f..c040a6ce 100644 --- a/tests/TestingUtils/TestObjects.CWL/Inputs.fs +++ b/tests/TestingUtils/TestObjects.CWL/Inputs.fs @@ -7,6 +7,9 @@ let inputsFileContent ="""inputs: inputBinding: position: 1 prefix: --example + argOptional: + type: File? + argOptionalMap: File[]? secondArg: type: string inputBinding: diff --git a/tests/TestingUtils/packages.lock.json b/tests/TestingUtils/packages.lock.json index a66a31c0..7583c57f 100644 --- a/tests/TestingUtils/packages.lock.json +++ b/tests/TestingUtils/packages.lock.json @@ -25,10 +25,10 @@ }, "Fable.Browser.Blob": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "xMX7hPFwBUGuj75xLlH6VsVThZjRlGW4zOqXb1X+byRPLSBE91vtn9EueNUB+YpGhE9LfrtakIPNGy+dkoMkjg==", + "resolved": "1.2.0", + "contentHash": "bM4zbtIeycTFFCH7o4WuN28W70dTxNTMZiMvR70XUTYrBnbz7GpS5XxzUy5caDB4l7s2l7wiuVDhh52t7NXxDg==", "dependencies": { - "FSharp.Core": "4.6.2", + "FSharp.Core": "4.7.2", "Fable.Core": "3.0.0" } }, @@ -46,10 +46,20 @@ }, "Fable.Browser.Event": { "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "T1bGrlRJ4A2fxOfAVPzJpxanR6lkzPgJroPdSN1IU5CLdKtvRakWmYq6QKqu4dz6ZV9Z3fIPTWLZkoGKEOEo3w==", + "resolved": "1.5.0", + "contentHash": "Bx2AOOASIG1Eq1Pe8869H8baMePte6STmKGccGuOYMT2p6nWVS8G6ZBZb5encQ0tAL2/0vhA4KJOl4bYwUaQqg==", "dependencies": { - "FSharp.Core": "4.5.2", + "FSharp.Core": "4.7.2", + "Fable.Browser.Gamepad": "1.1.0", + "Fable.Core": "3.0.0" + } + }, + "Fable.Browser.Gamepad": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "8m/Ae/mrH2Hb2ue435rTPEeVb2FhfWsRJJLpCxMvk+5EUOO2+IIjIkLq4thUfRL98uQVt9V5cQd14h2aBf2XJA==", + "dependencies": { + "FSharp.Core": "4.7.2", "Fable.Core": "3.0.0" } }, @@ -74,6 +84,15 @@ "Fable.Core": "3.0.0" } }, + "Fable.Promise": { + "type": "Transitive", + "resolved": "2.2.2", + "contentHash": "yHFSo7GCY0l/Wjskh/HESuFoGzXIoRM22UlrARA5ewnX736Y1wM27kcqCWeGcIzaEsgJnZcDkp093M0gQyMcWA==", + "dependencies": { + "FSharp.Core": "4.7.2", + "Fable.Core": "3.1.5" + } + }, "Fable.Python": { "type": "Transitive", "resolved": "4.3.0", @@ -130,15 +149,7 @@ "Fable.Core": "[4.3.0, )" } }, - "arctrl.json": { - "type": "Project", - "dependencies": { - "ARCtrl.Core": "[1.0.0, )", - "ARCtrl.ROCrate": "[1.0.0, )", - "Thoth.Json.Core": "[0.4.0, )" - } - }, - "arctrl.python": { + "arctrl.javascript": { "type": "Project", "dependencies": { "ARCtrl.CWL": "[1.0.0, )", @@ -147,7 +158,17 @@ "ARCtrl.Json": "[1.0.0, )", "ARCtrl.ROCrate": "[1.0.0, )", "ARCtrl.Spreadsheet": "[1.0.0, )", - "Thoth.Json.Python": "[0.4.0, )" + "Fable.Fetch": "[2.6.0, )", + "Fable.SimpleHttp": "[3.5.0, )", + "Thoth.Json.Javascript": "[0.3.0, )" + } + }, + "arctrl.json": { + "type": "Project", + "dependencies": { + "ARCtrl.Core": "[1.0.0, )", + "ARCtrl.ROCrate": "[1.0.0, )", + "Thoth.Json.Core": "[0.4.0, )" } }, "arctrl.rocrate": { @@ -195,6 +216,19 @@ "resolved": "4.3.0", "contentHash": "sbK+hYs7H7I3b3sbgttI4GlvQfNPcIqSz1qPSagF3QbVA46KJ/pWSXC/Dwv0s9M6AeRGmoqcIeD7GUaLn41zkA==" }, + "Fable.Fetch": { + "type": "CentralTransitive", + "requested": "[2.6.0, )", + "resolved": "2.6.0", + "contentHash": "zhCl95EYeuKcc7bk2jGHLSuLhkPqvRcrlwC91GqgX51BlQ7WJF2IQ7mUxW2n1mg74M1D2VOwEKqQpTAZDCVa8Q==", + "dependencies": { + "FSharp.Core": "4.7.2", + "Fable.Browser.Blob": "1.2.0", + "Fable.Browser.Event": "1.5.0", + "Fable.Core": "3.7.1", + "Fable.Promise": "2.2.2" + } + }, "Fable.SimpleHttp": { "type": "CentralTransitive", "requested": "[3.5.0, )", @@ -235,6 +269,18 @@ "Fable.Package.SDK": "1.0.0" } }, + "Thoth.Json.JavaScript": { + "type": "CentralTransitive", + "requested": "[0.3.0, )", + "resolved": "0.3.0", + "contentHash": "A4Cwv+RigC52/OdcrU2woEvjd6rsiDlQGDNTqwXYe3Yh6cdzcLWTfmmwTuCOXgV8SMbcSkviqiS2AG5BS42ayg==", + "dependencies": { + "FSharp.Core": "5.0.0", + "Fable.Core": "4.1.0", + "Fable.Package.SDK": "1.0.0", + "Thoth.Json.Core": "0.4.0" + } + }, "Thoth.Json.Newtonsoft": { "type": "CentralTransitive", "requested": "[0.2.0, )", @@ -248,19 +294,6 @@ "Thoth.Json.Core": "0.3.0" } }, - "Thoth.Json.Python": { - "type": "CentralTransitive", - "requested": "[0.4.0, )", - "resolved": "0.4.0", - "contentHash": "O86Oisv/91NpbHENz11poZh9zrTRJdAjDXHVC1JqvDDsscelI7HxOmWgks8ZFvYxbBzNJCG+FKQHC10KzyMf8g==", - "dependencies": { - "FSharp.Core": "5.0.0", - "Fable.Core": "4.1.0", - "Fable.Package.SDK": "1.0.0", - "Fable.Python": "4.3.0", - "Thoth.Json.Core": "0.4.0" - } - }, "YAMLicious": { "type": "CentralTransitive", "requested": "[0.0.3, )",