1 /**
2  * Hand-written definition of CWL v1.0 CommandLineTool
3  *
4  * Authors: Tomoya Tanjo
5  * Copyright: © 2021 Tomoya Tanjo
6  * License: Apache-2.0
7  */
8 module cwl.schema;
9 
10 import salad.context : LoadingContext;
11 import salad.exception;
12 import salad.meta;
13 import salad.type;
14 import salad.util;
15 
16 @documentRoot class CommandLineTool
17 {
18     @idMap("id", "type")
19     CommandInputParameter[] inputs_;
20     @idMap("id", "type")
21     CommandOutputParameter[] outputs_;
22     immutable class_ = "CommandLineTool";
23     @id Optional!string id_;
24     @idMap("class")
25     Optional!(
26         Either!(
27             InlineJavascriptRequirement,
28             SchemaDefRequirement,
29             DockerRequirement,
30             SoftwareRequirement,
31             InitialWorkDirRequirement,
32             EnvVarRequirement,
33             ShellCommandRequirement,
34             ResourceRequirement,
35         )[]
36     ) requirements_;
37     @idMap("class") Optional!(Any[]) hints_;
38     Optional!string label_;
39     Optional!string doc_;
40     Optional!CWLVersion cwlVersion_;
41     Optional!(string, string[]) baseCommand_;
42     Optional!(Either!(string, CommandLineBinding)[]) arguments_;
43     Optional!string stdin_;
44     Optional!string stderr_;
45     Optional!string stdout_;
46     Optional!(int[]) successCodes_;
47     Optional!(int[]) temporaryFailCodes_;
48     Optional!(int[]) permanentFailCodes_;
49 
50     mixin genCtor;
51     mixin genIdentifier;
52 }
53 
54 class CommandInputParameter
55 {
56     @id string id_;
57     Optional!string label_;
58     Optional!(string, string[]) secondaryFiles_;
59     Optional!bool streamable_;
60     Optional!(string, string[]) doc_;
61     Optional!(string, string[]) format_;
62     Optional!CommandLineBinding inputBinding_;
63     Optional!(
64         CWLType,
65         CommandInputRecordSchema,
66         CommandInputEnumSchema,
67         CommandInputArraySchema,
68         string,
69         Either!(
70             CWLType,
71             CommandInputRecordSchema,
72             CommandInputEnumSchema,
73             CommandInputArraySchema,
74             string
75         )[]
76     ) type_;
77 
78     mixin genCtor;
79     mixin genIdentifier;
80 }
81 
82 class CommandLineBinding
83 {
84     Optional!bool loadContents_;
85     Optional!int position_;
86     Optional!string prefix_;
87     Optional!bool separate_;
88     Optional!string itemSeparator_;
89     Optional!string valueFrom_;
90     Optional!bool shellQuote_;
91 
92     mixin genCtor;
93     mixin genIdentifier;
94 }
95 
96 class Any
97 {
98     import dyaml : Node, NodeType;
99 
100     Node value_;
101 
102     alias value_ this;
103 
104     this(Node node, in LoadingContext context = LoadingContext.init)
105     {
106         docEnforce(node.type != NodeType.null_,
107                    "Any should be non-null", node);
108         value_ = node;
109     }
110 }
111 
112 class CWLType
113 {
114     import dyaml : Node;
115 
116     enum Types{
117         null_ = "null",
118         boolean_ = "boolean",
119         int_ = "int",
120         long_ = "long",
121         float_ = "float",
122         double_ = "double",
123         string_ = "string",
124         File_ = "File",
125         Directory_ = "Directory",
126     }
127 
128     alias type_ this;
129 
130     string type_;
131 
132     this(in Node node, in LoadingContext context = LoadingContext.init) @safe
133     {
134         type_ = node.as!string;
135         // enforce
136     }
137 
138     bool opEquals(string s) const @nogc nothrow pure
139     {
140         return type_ == s;
141     }
142 }
143 
144 class File
145 {
146     immutable class_ = "File";
147     Optional!string location_;
148     Optional!string path_;
149     Optional!string basename_;
150     Optional!string dirname_;
151     Optional!string nameroot_;
152     Optional!string nameext_;
153     Optional!string checksum_;
154     Optional!int size_;
155     Optional!(Either!(File, Directory)[]) secondaryFiles_;
156     Optional!string format_;
157     Optional!string contents_;
158 
159     mixin genCtor;
160     mixin genIdentifier;
161 }
162 
163 class Directory
164 {
165     immutable class_ = "Directory";
166     Optional!string location_;
167     Optional!string path_;
168     Optional!string basename_;
169     Optional!(
170         Either!(File, Directory)[]
171     ) listing_;
172 
173     mixin genCtor;
174     mixin genIdentifier;
175 }
176 
177 class CommandInputRecordSchema
178 {
179     immutable type_ = "record";
180     @idMap("name", "type")
181     Optional!(CommandInputRecordField[]) fields_;
182     Optional!string label_;
183     Optional!string name_;
184 
185     mixin genCtor;
186     mixin genIdentifier;
187 }
188 
189 class CommandInputRecordField
190 {
191     string name_;
192     Either!(
193         CWLType,
194         CommandInputRecordSchema,
195         CommandInputEnumSchema,
196         CommandInputArraySchema,
197         string,
198         Either!(
199             CWLType,
200             CommandInputRecordSchema,
201             CommandInputEnumSchema,
202             CommandInputArraySchema,
203             string,
204         )[]
205     ) type_;
206     Optional!string doc_;
207     Optional!CommandLineBinding inputBinding_;
208     Optional!string label_;
209 
210     mixin genCtor;
211     mixin genIdentifier;
212 }
213 
214 class CommandInputEnumSchema
215 {
216     string[] symbols_;
217     immutable type_ = "enum";
218     Optional!string label_;
219     Optional!string name_;
220     Optional!CommandLineBinding inputBinding_;
221 
222     mixin genCtor;
223     mixin genIdentifier;
224 }
225 
226 class CommandInputArraySchema
227 {
228     Either!(
229         CWLType,
230         CommandInputRecordSchema,
231         CommandInputEnumSchema,
232         CommandInputArraySchema,
233         string,
234         Either!(
235             CWLType,
236             CommandInputRecordSchema,
237             CommandInputEnumSchema,
238             CommandInputArraySchema,
239             string,
240         )[],
241     ) items_;
242     immutable type_ = "array";
243     Optional!string label_;
244     Optional!CommandLineBinding inputBinding_;
245 
246     mixin genCtor;
247     mixin genIdentifier;
248 }
249 
250 class CommandOutputParameter
251 {
252     @id string id_;
253     Optional!string label_;
254     Optional!(string, string[]) secondaryFiles_;
255     Optional!bool streamable_;
256     Optional!(string, string[]) doc_;
257     Optional!CommandOutputBinding outputBinding_;
258     Optional!string format_;
259     Optional!(
260         CWLType,
261         stdout,
262         stderr,
263         CommandOutputRecordSchema,
264         CommandOutputEnumSchema,
265         CommandOutputArraySchema,
266         string,
267         Either!(
268             CWLType,
269             CommandOutputRecordSchema,
270             CommandOutputEnumSchema,
271             CommandOutputArraySchema,
272             string
273         )[],
274     ) type_;
275 
276     mixin genCtor;
277     mixin genIdentifier;
278 }
279 
280 class stdout
281 {
282     import dyaml : Node;
283 
284     enum Types{
285         stdout_ = "stdout",
286     }
287 
288     alias type_ this;
289 
290     string type_;
291 
292     this(in Node node, in LoadingContext context = LoadingContext.init) @safe
293     {
294         type_ = node.as!string;
295         // enforce
296     }
297 }
298 
299 class stderr
300 {
301     import dyaml : Node;
302 
303     enum Types{
304         stderr_ = "stderr",
305     }
306 
307     alias type_ this;
308 
309     string type_;
310 
311     this(in Node node, in LoadingContext context = LoadingContext.init) @safe
312     {
313         type_ = node.as!string;
314         // enforce
315     }
316 }
317 
318 class CommandOutputBinding
319 {
320     Optional!(string, string[]) glob_;
321     Optional!bool loadContents_;
322     Optional!string outputEval_;
323 
324     mixin genCtor;
325     mixin genIdentifier;
326 }
327 
328 class CommandOutputRecordSchema
329 {
330     immutable type_ = "record";
331     @idMap("name", "type")
332     Optional!(CommandOutputRecordField[]) fields_;
333     Optional!string label_;
334     @id Optional!string name_;
335 
336     mixin genCtor;
337     mixin genIdentifier;
338 }
339 
340 class CommandOutputRecordField
341 {
342     string name_;
343     Either!(
344         CWLType,
345         CommandOutputRecordSchema,
346         CommandOutputEnumSchema,
347         CommandOutputArraySchema,
348         string,
349         Either!(
350             CWLType,
351             CommandOutputRecordSchema,
352             CommandOutputEnumSchema,
353             CommandOutputArraySchema,
354             string,
355         )[],
356     ) type_;
357     Optional!string doc_;
358     Optional!CommandOutputBinding outputBinding_;
359 
360     mixin genCtor;
361     mixin genIdentifier;
362 }
363 
364 class CommandOutputEnumSchema
365 {
366     string[] symbols_;
367     immutable type_ = "enum";
368     Optional!string label_;
369     Optional!CommandOutputBinding outputBinding_;
370 
371     mixin genCtor;
372     mixin genIdentifier;
373 }
374 
375 class CommandOutputArraySchema
376 {
377     Either!(
378         CWLType,
379         CommandOutputRecordSchema,
380         CommandOutputEnumSchema,
381         CommandOutputArraySchema,
382         string,
383         Either!(
384             CWLType,
385             CommandOutputRecordSchema,
386             CommandOutputEnumSchema,
387             CommandOutputArraySchema,
388             string,
389         )[],
390     ) items_;
391     immutable type_ = "array";
392     Optional!string label_;
393     Optional!CommandOutputBinding outputBinding_;
394 
395     mixin genCtor;
396     mixin genIdentifier;
397 }
398 
399 class InlineJavascriptRequirement
400 {
401     immutable class_ = "InlineJavascriptRequirement";
402     Optional!(string[]) expressionLib_;
403 
404     mixin genCtor;
405     mixin genIdentifier;
406 }
407 
408 class SchemaDefRequirement
409 {
410     immutable class_ = "SchemaDefRequirement";
411     Either!(
412         InputRecordSchema,
413         InputEnumSchema,
414         InputArraySchema,
415     )[] types_;
416 
417     mixin genCtor;
418     mixin genIdentifier;
419 }
420 
421 class InputRecordSchema
422 {
423     immutable type_ = "record";
424     @idMap("name", "type")
425     Optional!(
426         InputRecordField[]
427     ) fields_;
428     Optional!string label_;
429     @id Optional!string name_;
430 
431     mixin genCtor;
432     mixin genIdentifier;
433 }
434 
435 class InputRecordField
436 {
437     string name_;
438     Either!(
439         CWLType,
440         InputRecordSchema,
441         InputEnumSchema,
442         InputArraySchema,
443         string,
444         Either!(
445             CWLType,
446             InputRecordSchema,
447             InputEnumSchema,
448             InputArraySchema,
449             string,
450         )[],
451     ) type_;
452     Optional!string doc_;
453     Optional!CommandLineBinding inputBinding_;
454     Optional!string label_;
455 
456     mixin genCtor;
457     mixin genIdentifier;
458 }
459 
460 class InputEnumSchema
461 {
462     string[] symbols_;
463     immutable type_ = "enum";
464     Optional!string label_;
465     @id Optional!string name_;
466     Optional!CommandLineBinding inpuBinding_;
467 
468     mixin genCtor;
469     mixin genIdentifier;
470 }
471 
472 class InputArraySchema
473 {
474     Either!(
475         CWLType,
476         InputRecordSchema,
477         InputEnumSchema,
478         InputArraySchema,
479         string,
480         Either!(
481             CWLType,
482             InputRecordSchema,
483             InputEnumSchema,
484             InputArraySchema,
485             string,
486         )[],
487     ) items_;
488     immutable type_ = "array";
489     Optional!string label_;
490     Optional!CommandLineBinding inputBinding_;
491 
492     mixin genCtor;
493     mixin genIdentifier;
494 }
495 
496 class DockerRequirement
497 {
498     immutable class_ = "DockerRequirement";
499     Optional!string dockerPull_;
500     Optional!string dockerLoad_;
501     Optional!string dockerFile_;
502     Optional!string dockerImport_;
503     Optional!string dockerImageId_;
504     Optional!string dockerOutputDirectory_;
505 
506     mixin genCtor;
507     mixin genIdentifier;
508 }
509 
510 class SoftwareRequirement
511 {
512     immutable class_ = "SoftwareRequirement";
513     @idMap("package", "specs")
514     SoftwarePackage[] packages_;
515 
516     mixin genCtor;
517     mixin genIdentifier;
518 }
519 
520 class SoftwarePackage
521 {
522     string package_;
523     Optional!(string[]) version_;
524     Optional!(string[]) specs_;
525 
526     mixin genCtor;
527     mixin genIdentifier;
528 }
529 
530 class InitialWorkDirRequirement
531 {
532     immutable class_ = "InitialWorkDirRequirement";
533     Either!(
534         Either!(
535             File,
536             Directory,
537             Dirent,
538             string,
539         )[],
540         string,
541     ) listing_;
542 
543     mixin genCtor;
544     mixin genIdentifier;
545 }
546 
547 class Dirent
548 {
549     string entry_;
550     Optional!string entryname_;
551     Optional!bool writable_;
552 
553     mixin genCtor;
554     mixin genIdentifier;
555 }
556 
557 class EnvVarRequirement
558 {
559     immutable class_ = "EnvVarRequirement";
560     @idMap("envName", "envValue")
561     EnvironmentDef[] envDef_;
562 
563     mixin genCtor;
564     mixin genIdentifier;
565 }
566 
567 class EnvironmentDef
568 {
569     string envName_;
570     string envValue_;
571 
572     mixin genCtor;
573     mixin genIdentifier;
574 }
575 
576 class ShellCommandRequirement
577 {
578     immutable class_ = "ShellCommandRequirement";
579 
580     mixin genCtor;
581     mixin genIdentifier;
582 }
583 
584 class ResourceRequirement
585 {
586     immutable class_ = "ResourceRequirement";
587     Optional!(long, string) coresMin_;
588     Optional!(int, string) coresMax_;
589     Optional!(long, string) ramMin_;
590     Optional!(long, string) ramMax_;
591     Optional!(long, string) tmpdirMin_;
592     Optional!(long, string) tmpdirMax_;
593     Optional!(long, string) outdirMin_;
594     Optional!(long, string) outdirMax_;
595 
596     mixin genCtor;
597     mixin genIdentifier;
598 }
599 
600 class CWLVersion
601 {
602     import dyaml : Node;
603 
604     enum Types{
605         draft_2	= "draft-2",
606         draft_3_dev1 = "draft-3.dev1",
607         draft_3_dev2 = "draft-3.dev2",
608         draft_3_dev3 = "draft-3.dev3",
609         draft_3_dev4 = "draft-3.dev4",
610         draft_3_dev5 = "draft-3.dev5",
611         draft_3 = "draft-3",
612         draft_4_dev1 = "draft-4.dev1",
613         draft_4_dev2 = "draft-4.dev2",
614         draft_4_dev3 = "draft-4.dev3",
615         v1_0_dev4 = "v1.0.dev4",
616         v1_0 = "v1.0",
617     }
618 
619     alias type_ this;
620 
621     string type_;
622 
623     this(in Node node, in LoadingContext context = LoadingContext.init) @safe
624     {
625         type_ = node.as!string;
626         // enforce
627     }
628 
629     bool opEquals(string s) const @nogc nothrow pure
630     {
631         return type_ == s;
632     }
633 }
634 
635 unittest
636 {
637     import dyaml;
638 
639     enum cwl = "examples/bwa-mem-tool.cwl";
640     auto cmd = Loader.fromFile(cwl)
641                      .load
642                      .as!CommandLineTool;
643     assert(cmd.dig!"cwlVersion"("v1.2") == "v1.0");
644     assert(cmd.dig!(["inputs", "reference", "type"], CWLType) == "File");
645     assert(cmd.dig!("hints", Any[])[0]
646               .as!ResourceRequirement
647               .dig!("coresMin", long) == 2);
648 }
649 
650 @documentRoot class Workflow
651 {
652     @idMap("id", "type")
653     InputParameter[] inputs_;
654     @idMap("id", "type")
655     WorkflowOutputParameter[] outputs_;
656     immutable class_ = "Workflow";
657     @idMap("id") WorkflowStep[] steps_;
658     @id Optional!string id_;
659     @idMap("class")
660     Optional!(
661         Either!(
662             InlineJavascriptRequirement,
663             SchemaDefRequirement,
664             DockerRequirement,
665             SoftwareRequirement,
666             InitialWorkDirRequirement,
667             EnvVarRequirement,
668             ShellCommandRequirement,
669             ResourceRequirement,
670             SubworkflowFeatureRequirement,
671             ScatterFeatureRequirement,
672             MultipleInputFeatureRequirement,
673             StepInputExpressionRequirement,
674         )[]
675     ) requirements_;
676     @idMap("class") Optional!(Any[]) hints_;
677     Optional!string label_;
678     Optional!string doc_;
679     Optional!CWLVersion cwlVersion_;
680 
681     mixin genCtor;
682     mixin genIdentifier;
683 }
684 
685 class WorkflowOutputParameter
686 {
687     @id string id_;
688     Optional!string label_;
689     Optional!(string, string[]) secondaryFiles_;
690     Optional!bool streamable_;
691     Optional!(string, string[]) doc_;
692     Optional!CommandOutputBinding outputBinding_;
693     Optional!string format_;
694     Optional!(string, string[]) outputSource_;
695     Optional!LinkMergeMethod linkMerge_;
696     Optional!(
697         CWLType,
698         OutputRecordSchema,
699         OutputEnumSchema,
700         OutputArraySchema,
701         string,
702         Either!(
703             CWLType,
704             OutputRecordSchema,
705             OutputEnumSchema,
706             OutputArraySchema,
707             string,
708         )[],
709     ) type_;
710 
711     mixin genCtor;
712     mixin genIdentifier;
713 }
714 
715 class LinkMergeMethod
716 {
717     import dyaml : Node;
718 
719     enum Types{
720         merge_nested_ = "merge_nested",
721         merge_flattened_ = "merge_flattened",
722     }
723 
724     alias type_ this;
725 
726     string type_;
727 
728     this(in Node node, in LoadingContext context = LoadingContext.init) @safe
729     {
730         type_ = node.as!string;
731     }
732 }
733 
734 class OutputRecordSchema
735 {
736     immutable type_ = "record";
737     @idMap("name", "type")
738     Optional!(OutputRecordField[]) fields_;
739     Optional!string label_;
740 
741     mixin genCtor;
742     mixin genIdentifier;
743 }
744 
745 class OutputRecordField
746 {
747     string name_;
748     Either!(
749         CWLType,
750         OutputRecordSchema,
751         OutputEnumSchema,
752         OutputArraySchema,
753         string,
754         Either!(
755             CWLType,
756             OutputRecordSchema,
757             OutputEnumSchema,
758             OutputArraySchema,
759             string,
760         )[],
761     ) type_;
762     Optional!string doc_;
763     Optional!CommandOutputBinding outputBinding_;
764 
765     mixin genCtor;
766     mixin genIdentifier;
767 }
768 
769 class OutputEnumSchema
770 {
771     string[] symbols_;
772     immutable type_ = "enum";
773     Optional!string label_;
774     Optional!CommandOutputBinding outputBinding_;
775 
776     mixin genCtor;
777     mixin genIdentifier;
778 }
779 
780 class OutputArraySchema
781 {
782     Either!(
783         CWLType,
784         OutputRecordSchema,
785         OutputEnumSchema,
786         OutputArraySchema,
787         string,
788         Either!(
789             CWLType,
790             OutputRecordSchema,
791             OutputEnumSchema,
792             OutputArraySchema,
793             string,
794         )[],
795     ) items_;
796     immutable type_ = "array";
797     Optional!string label_;
798     Optional!CommandOutputBinding outputBinding_;
799 
800     mixin genCtor;
801     mixin genIdentifier;
802 }
803 
804 class WorkflowStep
805 {
806     @id string id_;
807     @idMap("id", "source")
808     WorkflowStepInput[] in_;
809     Either!(string, WorkflowStepOutput)[] out_;
810     Either!(string, CommandLineTool, ExpressionTool, Workflow) run_;
811     @idMap("class")
812     Optional!(
813         Either!(
814             InlineJavascriptRequirement,
815             SchemaDefRequirement,
816             DockerRequirement,
817             SoftwareRequirement,
818             InitialWorkDirRequirement,
819             EnvVarRequirement,
820             ShellCommandRequirement,
821             ResourceRequirement,
822             SubworkflowFeatureRequirement,
823             ScatterFeatureRequirement,
824             MultipleInputFeatureRequirement,
825             StepInputExpressionRequirement,
826         )[]
827     ) requirements_;
828     @idMap("class") Optional!(Any[]) hints_;
829     Optional!string label_;
830     Optional!string doc_;
831     Optional!(string, string[]) scatter_;
832     Optional!ScatterMethod scatterMethod_;
833 
834     mixin genCtor;
835     mixin genIdentifier;
836 }
837 
838 class WorkflowStepInput
839 {
840     @id string id_;
841     Optional!(string, string[]) source_;
842     Optional!LinkMergeMethod linkMerge_;
843     Optional!Any default_;
844     Optional!string valueFrom_;
845 
846     mixin genCtor;
847     mixin genIdentifier;
848 }
849 
850 class WorkflowStepOutput
851 {
852     @id string id_;
853 
854     mixin genCtor;
855     mixin genIdentifier;
856 }
857 
858 class ScatterMethod
859 {
860     import dyaml : Node;
861 
862     enum Types{
863         dotproduct_ = "dotproduct",
864         nested_crossproduct_ = "nested_crossproduct",
865         flat_crossproduct_ = "flat_crossproduct_",
866     }
867 
868     alias type_ this;
869 
870     string type_;
871 
872     this(in Node node, in LoadingContext context = LoadingContext.init) @safe
873     {
874         type_ = node.as!string;
875         // enforce
876     }
877 }
878 
879 class SubworkflowFeatureRequirement
880 {
881     immutable class_ = "SubworkflowFeatureRequirement";
882 
883     mixin genCtor;
884     mixin genIdentifier;
885 }
886 
887 class ScatterFeatureRequirement
888 {
889     immutable class_ = "ScatterFeatureRequirement";
890 
891     mixin genCtor;
892     mixin genIdentifier;
893 }
894 
895 class MultipleInputFeatureRequirement
896 {
897     immutable class_ = "MultipleInputFeatureRequirement";
898 
899     mixin genCtor;
900     mixin genIdentifier;
901 }
902 
903 class StepInputExpressionRequirement
904 {
905     immutable class_ = "StepInputExpressionRequirement";
906 
907     mixin genCtor;
908     mixin genIdentifier;
909 }
910 
911 @documentRoot class ExpressionTool
912 {
913     @idMap("id", "type")
914     InputParameter[] inputs_;
915     @idMap("id", "type")
916     ExpressionToolOutputParameter[] outputs_;
917     immutable class_ = "Expression";
918     string expression_;
919     @id Optional!string id_;
920     @idMap("class")
921     Optional!(
922         Either!(
923             InlineJavascriptRequirement,
924             SchemaDefRequirement,
925             DockerRequirement,
926             SoftwareRequirement,
927             InitialWorkDirRequirement,
928             EnvVarRequirement,
929             ShellCommandRequirement,
930             ResourceRequirement,
931             SubworkflowFeatureRequirement,
932             ScatterFeatureRequirement,
933             MultipleInputFeatureRequirement,
934             StepInputExpressionRequirement,
935         )[]
936     ) requirements_;
937     @idMap("class") Optional!(Any[]) hints_;
938     Optional!string label_;
939     Optional!string doc_;
940     Optional!CWLVersion cwlVersion_;
941 
942     mixin genCtor;
943     mixin genIdentifier;
944 }
945 
946 class InputParameter
947 {
948     @id string id_;
949     Optional!string label_;
950     Optional!(string, string[]) secondaryFiles_;
951     Optional!bool streamable_;
952     Optional!(string, string[]) doc_;
953     Optional!(string, string[]) format_;
954     Optional!CommandLineBinding inputBinding_;
955     Optional!Any default_;
956     Optional!(
957         CWLType,
958         InputRecordSchema,
959         InputEnumSchema,
960         InputArraySchema,
961         string,
962         Either!(
963             CWLType,
964             InputRecordSchema,
965             InputEnumSchema,
966             InputArraySchema,
967             string,
968         )[],
969     ) type_;
970 
971     mixin genCtor;
972     mixin genIdentifier;
973 }
974 
975 class ExpressionToolOutputParameter
976 {
977     @id string id_;
978     Optional!string label_;
979     Optional!(string, string[]) secondaryFiles_;
980     Optional!bool streamable_;
981     Optional!(string, string[]) doc_;
982     Optional!CommandOutputBinding outputBinding_;
983     Optional!string format_;
984     Optional!(
985         CWLType,
986         OutputRecordSchema,
987         OutputEnumSchema,
988         OutputArraySchema,
989         string,
990         Either!(
991             CWLType,
992             OutputRecordSchema,
993             OutputEnumSchema,
994             OutputArraySchema,
995             string,
996         )[],
997     ) type_;
998 
999     mixin genCtor;
1000     mixin genIdentifier;
1001 }
1002 
1003 unittest
1004 {
1005     import dyaml;
1006 
1007     enum cwl = "examples/count-lines1-wf.cwl";
1008     auto wf = Loader.fromFile(cwl)
1009                     .load
1010                     .as!Workflow;
1011     assert(wf.dig!"class"("Invalid") == "Workflow");
1012     assert(wf.dig!"cwlVersion"("v1.2") == "v1.0");
1013     assert(wf.dig!(["inputs", "file1", "type"], CWLType) == "File");
1014     assert(wf.dig!(["outputs", "count_output", "outputSource"], string) == "step2/output");
1015 }