Skip to content

Commit

Permalink
Merge pull request #129 from rabix/maint/march-2021
Browse files Browse the repository at this point in the history
Maint/march 2021
  • Loading branch information
milosdanilov authored Mar 31, 2021
2 parents d3dd616 + 9d935db commit c0a74df
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 49 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cwlts",
"version": "1.20.1",
"version": "1.21.0",
"description": "TypeScript data model for Common Workflow Language",
"scripts": {
"tsc": "npx tsc",
Expand Down
13 changes: 1 addition & 12 deletions src/models/d2sb/SBDraft2CommandLineToolModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,18 +320,7 @@ export class SBDraft2CommandLineToolModel extends CommandLineToolModel implement

this.baseCommand = [];

(<Array<string | Expression>> tool.baseCommand).reduce((acc, curr) => {
if (typeof curr === "string") {
if (typeof acc[acc.length - 1] === "string") {
acc[acc.length - 1] += ` ${curr}`;
return acc;
} else {
return acc.concat([curr]);
}
} else {
return acc.concat([curr]);
}
}, []).forEach((cmd) => {
tool.baseCommand.forEach((cmd) => {
this.addBaseCommand(cmd);
});

Expand Down
4 changes: 2 additions & 2 deletions src/models/d2sb/SBDraft2CommandOutputBindingModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class SBDraft2CommandOutputBindingModel extends CommandOutputBindingModel
}

set glob(value: SBDraft2ExpressionModel) {
this.setGlob(value, SBDraft2ExpressionModel);
this.setGlobExpression(value, SBDraft2ExpressionModel);
}

protected _outputEval: SBDraft2ExpressionModel;
Expand Down Expand Up @@ -152,4 +152,4 @@ export class SBDraft2CommandOutputBindingModel extends CommandOutputBindingModel
});
}
}
}
}
47 changes: 26 additions & 21 deletions src/models/generic/CommandOutputBindingModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ export abstract class CommandOutputBindingModel extends ValidationBase implement

secondaryFiles: ExpressionModel[];

glob: ExpressionModel;
glob: ExpressionModel | Array<string>;

protected _glob: ExpressionModel;
protected _glob: ExpressionModel | Array<string>;

loadContents: boolean;

Expand All @@ -36,27 +36,21 @@ export abstract class CommandOutputBindingModel extends ValidationBase implement

abstract deserialize(attr: any): void;

protected setGlob(value: ExpressionModel, exprConstructor: new (...args: any[]) => ExpressionModel) {
let val = value.serialize();
this._glob.clearIssue(ErrorCode.ALL);
this._glob = new exprConstructor(val, `${this.loc}.glob`, this.eventHub);
this._glob.setValidationCallback(err => this.updateValidity(err));
this.validateGlob();
}

protected validateGlob() {
if (!this._glob) return;

if (this._glob.serialize() === undefined) {
this._glob.setIssue({
[`${this.loc}.glob`]: {
message: "Glob should be specified",
type: "warning",
code: ErrorCode.OUTPUT_GLOB_MISSING
}
}, true);
} else {
this._glob.clearIssue(ErrorCode.OUTPUT_GLOB_MISSING);
if (this._glob instanceof ExpressionModel) {
if (this._glob.serialize() === undefined) {
this._glob.setIssue({
[`${this.loc}.glob`]: {
message: "Glob should be specified",
type: "warning",
code: ErrorCode.OUTPUT_GLOB_MISSING
}
}, true);
} else {
this._glob.clearIssue(ErrorCode.OUTPUT_GLOB_MISSING);
}
}
}

Expand All @@ -67,4 +61,15 @@ export abstract class CommandOutputBindingModel extends ValidationBase implement
this._outputEval = new exprConstructor(value.serialize(), `${this.loc}.outputEval`, this.eventHub);
this._outputEval.setValidationCallback(err => this.updateValidity(err));
}
}

protected setGlobExpression(expression: ExpressionModel, exprConstructor: new (...args: any[]) => ExpressionModel) {
if (this._glob instanceof ExpressionModel) {
this._glob.clearIssue(ErrorCode.ALL);
}

this._glob = new exprConstructor(expression.serialize(), `${this.loc}.glob`, this.eventHub);
this._glob.setValidationCallback(err => this.updateValidity(err));
this.validateGlob();
}

}
15 changes: 15 additions & 0 deletions src/models/helpers/Glob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {V1ExpressionModel} from "../v1.0";

export function toExpression(array: Array<string>): V1ExpressionModel {
return array.length === 1 ? new V1ExpressionModel(array[0]) : new V1ExpressionModel();
}

export function toArray(expression: V1ExpressionModel): Array<string> {
const strExpression = expression.serialize();

if (expression.isExpression) {
return [];
}

return strExpression ? [strExpression] : [];
}
75 changes: 74 additions & 1 deletion src/models/helpers/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import {
CommandInputParameterModel,
CommandOutputParameterModel,
ExpressionModel,
ParameterTypeModel,
WorkflowOutputParameterModel
StepModel,
WorkflowInputParameterModel,
WorkflowOutputParameterModel,
} from "../generic";
import {InputParameterModel} from "../generic/InputParameterModel";
import {ErrorCode, Issue, ValidityError} from "./validation";
Expand Down Expand Up @@ -288,6 +291,36 @@ export const checkIfConnectionIsValid = (pointA, pointB, ltr = true) => {
}
};

const stepHasScatterInput = (step: StepModel, scatter: string) => {
return ensureArray(step.scatter).some(s => s == scatter);
};

const checkBothPointsForSameScatter = () => {
if (pointA instanceof WorkflowInputParameterModel ||
pointA instanceof WorkflowOutputParameterModel ||
pointB instanceof WorkflowInputParameterModel ||
pointB instanceof WorkflowOutputParameterModel) {
return true;
}

if (pointB.parentStep && pointA.parentStep) {
const stepBHasDefinedScatter = stepHasScatterInput(pointB.parentStep, pointB.id);
const stepAHasDefinedScatter = stepHasScatterInput(pointA.parentStep, pointB.id);

if ((!stepAHasDefinedScatter && stepBHasDefinedScatter) ||
(stepAHasDefinedScatter && !stepBHasDefinedScatter)) {
throw new ValidityError(
`Invalid connection. Scatter '${pointB.id}' is making a mismatch in connection`,
ErrorCode.CONNECTION_SCATTER_TYPE
);
}

return true;
}

return true;
}

// fetch type
const pointAType = pointA.type.type;
const pointBType = pointB.type.type;
Expand Down Expand Up @@ -334,10 +367,50 @@ export const checkIfConnectionIsValid = (pointA, pointB, ltr = true) => {
}
}

if (pointAType === pointBType) {
checkBothPointsForSameScatter();
}

if (pointB.secondaryFiles.length) {

if (pointB.secondaryFiles.length > pointA.secondaryFiles.length) {
throw new ValidityError(`Input connection is missing required secondary files`, ErrorCode.CONNECTION_SEC_FILES);
}

const isRequired = (secondaryFile): boolean => secondaryFile.required !== undefined ? secondaryFile.required : true;
const getPattern = (secondaryFile): ExpressionModel => secondaryFile.pattern ? secondaryFile.pattern : secondaryFile;

const requiredSecondaryFiles = pointB.secondaryFiles
.filter(isRequired)
.map(getPattern);

const outputSecondaryFiles = pointA.secondaryFiles.map(getPattern);

requiredSecondaryFiles.forEach(secondaryFile => {
if (secondaryFile.isExpression) {
return;
}

const secondaryFilePattern = `${secondaryFile}`;
const foundSamePattern = outputSecondaryFiles.find(sf => sf.toString().toUpperCase() === secondaryFilePattern.toUpperCase());

if (!foundSamePattern) {
throw new ValidityError(`Input connection is missing required secondary files with a pattern: ${secondaryFilePattern}`, ErrorCode.CONNECTION_SEC_FILES);
}
});

return true;
}

// if not file or fileTypes not defined
return true;
}

// mark connection as valid if pointB has scatter and pointA[]
if ((pointAItems === pointBType) && stepHasScatterInput(pointB.parentStep, pointB.id)) {
return true;
}

// if types are both defined and do not match
const pointATypeOutput = pointAItems ? `"${pointAItems}[]"` : `"${pointAType}"`;
const pointBTypeOutput = pointBItems ? `"${pointBItems}[]"` : `"${pointBType}"`;
Expand Down
2 changes: 2 additions & 0 deletions src/models/helpers/validation/ErrorCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export enum ErrorCode {
CONNECTION_TYPE = 301,
CONNECTION_FILE_TYPE = 302,
CONNECTION_SAME_STEP = 303,
CONNECTION_SCATTER_TYPE = 304,
CONNECTION_SEC_FILES = 305,

OUTPUT_ALL = 400,
OUTPUT_GLOB_MISSING = 401,
Expand Down
38 changes: 27 additions & 11 deletions src/models/v1.0/V1CommandOutputBindingModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ export class V1CommandOutputBindingModel extends CommandOutputBindingModel {
static INHERIT_REGEX = /.*(?:\s*)inheritMetadata\((?:\s*)self(?:\s*),(?:\s*)inputs.(.*?)(?:\s*)\)(?:\s*).*/g;
public inheritMetadataFrom: string;

protected _glob: V1ExpressionModel;
protected _glob: V1ExpressionModel | Array<string>;

get glob(): V1ExpressionModel {
get glob(): V1ExpressionModel | Array<string> {
return this._glob;
}

set glob(value: V1ExpressionModel) {
this.setGlob(value, V1ExpressionModel);
set glob(value: V1ExpressionModel | Array<string>) {
if (value instanceof V1ExpressionModel) {
this.setGlobExpression(value, V1ExpressionModel);
} else {
this._glob = value;
}
}

protected _outputEval: V1ExpressionModel;
Expand Down Expand Up @@ -81,15 +85,14 @@ export class V1CommandOutputBindingModel extends CommandOutputBindingModel {
}

public deserialize(binding: CommandOutputBinding) {
let glob = binding.glob;

if (Array.isArray(binding.glob)) {
glob = binding.glob[0];
this._glob = binding.glob;
return;
}

this.loadContents = binding.loadContents === true;

this._glob = new V1ExpressionModel(<string> glob, `${this.loc}.glob`, this.eventHub);
this._glob = new V1ExpressionModel(<string> binding.glob, `${this.loc}.glob`, this.eventHub);
this._glob.setValidationCallback(err => this.updateValidity(err));
this.validateGlob();

Expand All @@ -108,10 +111,23 @@ export class V1CommandOutputBindingModel extends CommandOutputBindingModel {
public serialize(): CommandOutputBinding {
let base: CommandOutputBinding = <CommandOutputBinding> {};

if (this.loadContents) base.loadContents = true;
if (this.loadContents) {
base.loadContents = true;
}

if (this._glob) {
const globSerialized = this._glob instanceof V1ExpressionModel
? this._glob.serialize()
: this._glob;

if (this._glob && this._glob.serialize() !== undefined) base.glob = this._glob.serialize();
if (this._outputEval && this._outputEval.serialize() !== undefined) base.outputEval = this._outputEval.serialize();
if (globSerialized) {
base.glob = globSerialized;
}
}

if (this._outputEval && this._outputEval.serialize() !== undefined) {
base.outputEval = this._outputEval.serialize();
}

return base;
}
Expand Down

0 comments on commit c0a74df

Please sign in to comment.