1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import { Resource, ResourceKind } from "./resource";
6 import { safeLoad } from 'js-yaml';
7 import { CommandOutputParameter } from "cwlts/mappings/v1.0/CommandOutputParameter";
9 export interface WorkflowResource extends Resource {
10 kind: ResourceKind.WORKFLOW;
15 export interface WorkflowResourceDefinition {
17 $graph?: Array<Workflow | CommandLineTool>;
19 export interface Workflow {
23 inputs: CommandInputParameter[];
26 hints?: ProcessRequirement[];
29 export interface CommandLineTool {
30 class: 'CommandLineTool';
32 inputs: CommandInputParameter[];
34 hints?: ProcessRequirement[];
37 export type ProcessRequirement = GenericProcessRequirement | WorkflowRunnerResources;
39 export interface GenericProcessRequirement {
43 export interface WorkflowRunnerResources {
44 class: 'http://arvados.org/cwl#WorkflowRunnerResources';
48 acrContainerImage?: string;
51 export type CommandInputParameter =
52 BooleanCommandInputParameter |
53 IntCommandInputParameter |
54 LongCommandInputParameter |
55 FloatCommandInputParameter |
56 DoubleCommandInputParameter |
57 StringCommandInputParameter |
58 FileCommandInputParameter |
59 DirectoryCommandInputParameter |
60 StringArrayCommandInputParameter |
61 IntArrayCommandInputParameter |
62 FloatArrayCommandInputParameter |
63 FileArrayCommandInputParameter |
64 DirectoryArrayCommandInputParameter |
65 EnumCommandInputParameter;
76 DIRECTORY = 'Directory',
79 export interface CommandInputEnumSchema {
86 export interface CommandInputArraySchema<ItemType> {
92 export interface File {
99 export interface Directory {
100 class: CWLType.DIRECTORY;
106 export interface SecretInclude {
110 export interface GenericCommandInputParameter<Type, Value> {
113 doc?: string | string[];
115 type?: Type | Array<Type | CWLType.NULL>;
120 export type GenericArrayCommandInputParameter<Type, Value> = GenericCommandInputParameter<CommandInputArraySchema<Type>, Value[]>;
122 export type BooleanCommandInputParameter = GenericCommandInputParameter<CWLType.BOOLEAN, boolean>;
123 export type IntCommandInputParameter = GenericCommandInputParameter<CWLType.INT, number>;
124 export type LongCommandInputParameter = GenericCommandInputParameter<CWLType.LONG, number>;
125 export type FloatCommandInputParameter = GenericCommandInputParameter<CWLType.FLOAT, number>;
126 export type DoubleCommandInputParameter = GenericCommandInputParameter<CWLType.DOUBLE, number>;
127 export type StringCommandInputParameter = GenericCommandInputParameter<CWLType.STRING, string>;
128 export type FileCommandInputParameter = GenericCommandInputParameter<CWLType.FILE, File>;
129 export type DirectoryCommandInputParameter = GenericCommandInputParameter<CWLType.DIRECTORY, Directory>;
130 export type EnumCommandInputParameter = GenericCommandInputParameter<CommandInputEnumSchema, string>;
132 export type StringArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.STRING, string>;
133 export type IntArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.INT, string>;
134 export type FloatArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.FLOAT, string>;
135 export type FileArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.FILE, File>;
136 export type DirectoryArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.DIRECTORY, Directory>;
137 export type SecretCommandInputParameter = GenericArrayCommandInputParameter<CWLType.STRING, SecretInclude>;
140 export type WorkflowInputsData = {
141 [key: string]: boolean | number | string | File | Directory | SecretInclude;
143 export const parseWorkflowDefinition = (workflow: WorkflowResource): WorkflowResourceDefinition => {
144 const definition = safeLoad(workflow.definition);
148 export const getWorkflow = (workflowDefinition: WorkflowResourceDefinition) => {
149 if (!workflowDefinition.$graph) { return undefined; }
150 const mainWorkflow = workflowDefinition.$graph.find(item => item.id === '#main');
156 export interface CwlSecrets {
157 class: 'http://commonwl.org/cwltool#Secrets';
161 export const getWorkflowInputs = (workflowDefinition: WorkflowResourceDefinition) => {
162 if (!workflowDefinition) { return undefined; }
163 const wf = getWorkflow(workflowDefinition);
164 if (!wf) { return undefined; }
165 const inputs = wf.inputs;
167 const secrets = wf.hints.find(item => item.class === 'http://commonwl.org/cwltool#Secrets') as CwlSecrets | undefined;
168 if (secrets?.secrets) {
169 inputs.forEach((param) => {
170 param.secret = secrets.secrets.includes(param.id);
179 export const getWorkflowOutputs = (workflowDefinition: WorkflowResourceDefinition) => {
180 if (!workflowDefinition) { return undefined; }
181 return getWorkflow(workflowDefinition)
182 ? getWorkflow(workflowDefinition)!.outputs
186 export const getInputLabel = (input: CommandInputParameter) => {
187 return `${input.label || input.id.split('/').pop()}`;
190 export const getIOParamId = (input: CommandInputParameter | CommandOutputParameter) => {
191 return `${input.id.split('/').pop()}`;
194 export const isRequiredInput = ({ type }: CommandInputParameter) => {
195 if (type instanceof Array) {
196 for (const t of type) {
197 if (t === CWLType.NULL) {
205 export const isPrimitiveOfType = (input: GenericCommandInputParameter<any, any>, type: CWLType) =>
206 input.type instanceof Array
207 ? input.type.indexOf(type) > -1
208 : input.type === type;
210 export const isArrayOfType = (input: GenericCommandInputParameter<any, any>, type: CWLType) =>
211 input.type instanceof Array
212 ? (input.type.filter(t => typeof t === 'object' &&
213 t.type === 'array' &&
214 t.items === type).length > 0)
215 : (typeof input.type === 'object' &&
216 input.type.type === 'array' &&
217 input.type.items === type);
219 export const getEnumType = (input: GenericCommandInputParameter<any, any>) => {
220 if (input.type instanceof Array) {
221 const f = input.type.filter(t => typeof t === 'object' &&
222 !(t instanceof Array) &&
228 if ((typeof input.type === 'object' &&
229 !(input.type instanceof Array) &&
230 input.type.type === 'enum')) {
237 export const isSecret = (input: GenericCommandInputParameter<any, any>) =>
238 (typeof input.value === 'object') && input.value.$include?.startsWith("/secrets/");
240 export const stringifyInputType = ({ type }: CommandInputParameter) => {
241 if (typeof type === 'string') {
243 } else if (type instanceof Array) {
244 return type.join(' | ');
245 } else if (typeof type === 'object') {
246 if (type.type === 'enum') {
248 } else if (type.type === 'array') {
249 return `${type.items}[]`;