Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 214 additions & 19 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,24 @@
"lodash": "^4.17.21",
"mathjs": "^3.9.0",
"mixwith": "^0.1.1",
"underscore": "^1.13.3"
"underscore": "^1.13.3",
"underscore.string": "^3.3.4"
},
"devDependencies": {
"chai": "^4.3.4",
"eslint": "7.32.0",
"eslint-config-airbnb": "19.0.2",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-react": "^7.30.0",
"eslint-plugin-import": "2.25.3",
"eslint-plugin-jsdoc": "37.1.0",
"eslint-plugin-jsx-a11y": "6.5.1",
"eslint-plugin-prettier": "4.0.0",
"eslint-plugin-simple-import-sort": "7.0.0",
"husky": "^7.0.4",
"lint-staged": "^12.1.2",
"mocha": "^9.1.3",
"nyc": "^15.1.0"
"nyc": "^15.1.0",
"prettier": "^2.7.1"
},
"engines": {
"node": ">=12.0.0"
Expand Down
20 changes: 18 additions & 2 deletions src/entity/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import {
DefaultableInMemoryEntity,
NamedDefaultableInMemoryEntity,
HasMetadataNamedDefaultableInMemoryEntity,
NamedDefaultableRepetitionContextAndRenderInMemoryEntity,
NamedDefaultableRepetitionImportantSettingsInMemoryEntity,
NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity,
} from "./other";

import {
Expand All @@ -15,15 +18,22 @@ import {
HasMetadataMixin,
TaggableMixin,
NamedEntityMixin,
} from "./mixins";
} from "./mixins/props";

import { HashedInputArrayMixin } from "./mixins/hash";
import { RuntimeItemsMixin } from "./mixins/runtime_items";
import { RuntimeContextFieldMixin } from "./mixins/context_runtime";

import { InMemoryEntitySet } from "./set";
import { ENTITY_SET_TYPES } from "./set/enums";

import { constructEntitySetFactoryByConfig } from "./set/factory";
import { InMemoryEntitySetMixin, InMemoryEntityInSetMixin } from "./set/mixins";
import * as selectorsForEntitySet from "./set/selectors";
import { OrderedInMemoryEntityInSetMixin, OrderedInMemoryEntitySetMixin } from "./set/ordered/mixins";
import {
OrderedInMemoryEntityInSetMixin,
OrderedInMemoryEntitySetMixin,
} from "./set/ordered/mixins";

export {

Expand All @@ -32,12 +42,18 @@ export {
DefaultableInMemoryEntity,
NamedDefaultableInMemoryEntity,
HasMetadataNamedDefaultableInMemoryEntity,
NamedDefaultableRepetitionContextAndRenderInMemoryEntity,
NamedDefaultableRepetitionImportantSettingsInMemoryEntity,
NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity,

DefaultableMixin,
HasDescriptionMixin,
HasMetadataMixin,
TaggableMixin,
NamedEntityMixin,
RuntimeItemsMixin,
RuntimeContextFieldMixin,
HashedInputArrayMixin,

InMemoryEntitySet,
ENTITY_SET_TYPES,
Expand Down
66 changes: 0 additions & 66 deletions src/entity/mixins.js

This file was deleted.

90 changes: 90 additions & 0 deletions src/entity/mixins/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { deepClone } from "../../utils/clone";

export const ContextAndRenderFieldsMixin = (superclass) => {
return class extends superclass {
constructor(config) {
super(config);
this._context = config.context || {};
}

// in-memory, or "volatile" context that is reset when the `parent` object is destroyed
get context() {
return this._context;
}

set context(newContext) {
this._context = newContext;
}

updateContext(ctx = {}, executeRender = false) {
this._context = Object.assign({}, this.context, ctx);
executeRender && this.render();
}

// to get "persistent" context, that is stored in database and further should be provided to constructor
// when the `parent` object is re-created
getPersistentContext() {
return this.prop("context");
}

// to make context persistent in `_json`
updatePersistentContext(ctx = {}) {
this.setProp("context", Object.assign({}, ctx));
}

// to get persistent and volatile context combined
getCombinedContext() {
return Object.assign({}, this.getPersistentContext(), this.context);
}

// override in subclasses
render(context = this.context) {
throw new Error("RenderInitMixin: render not implemented in derived class");
}
};
};

/*
* @summary Handles logic for domain-specific context, eg. "important settings".
* Important settings are stored inside "important" property and have context providers associated with it.
*/
export const DomainContextProviderMixin = (superclass) => {
return class extends superclass {
constructor(config) {
super(config);
this._contextProviders = [];
}

get contextProviders() {
// override in children
return this._contextProviders;
}
};
};

export const ImportantSettingsProviderMixin = (superclass) => {
return class extends DomainContextProviderMixin(superclass) {
get important() {
return deepClone(this._json.important || {});
}

setImportant(key, value) {
this.setProp("important", {[key]: value})
}

/**
* @return {JSONSchemaFormDataProvider[]}
*/
get importantSettingsProviders() {
return this.contextProviders.filter(p => p.domain === "important");
}

get isImportantEdited() {
return this.prop("important.isEdited");
}

set isImportantEdited(bool) {
this.setProp("important", Object.assign(this.important, {isEdited: bool}));
}
};
};
25 changes: 25 additions & 0 deletions src/entity/mixins/context_runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const RuntimeContextFieldMixin = (superclass) => {
return class extends superclass {
constructor(config) {
super(config);
this._runtimeContext = config.runtimeContext || {};
}

// in-memory, or "volatile" runtimeContext that is reset when the `parent` object is destroyed
get runtimeContext() {
return this._runtimeContext;
}

set runtimeContext(newContext) {
this._runtimeContext = newContext;
}

updateRuntimeContext(ctx = {}) {
this.runtimeContext = Object.assign(this._runtimeContext, ctx);
}

toJSON() {
return Object.assign({}, super.toJSON(), {runtimeContext: this._runtimeContext});
}
};
};
37 changes: 37 additions & 0 deletions src/entity/mixins/hash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { calculateHashFromObject } from "../../utils/hash";
import { removeCommentsFromSourceCode, removeEmptyLinesFromString } from "../../utils/str";

export const HashedEntityMixin = (superclass) => {
return class extends superclass {
/*
* @summary Returns an object based on meaningful fields for this unit, that will be used to calculate the hash
* Must be overridden.
*/
getHashObject() {
return {};
}

/**
* @summary Calculates hash based on meaningful fields and unit-specific fields. Unit-specific fields are
* separated into _typeSpecificHash function which can be overwritten by child classes.
* head and next are also important but not considered since they are included in subworkflow hash.
*/
calculateHash() {
return calculateHashFromObject(this.getHashObject());
}
};
};

export const HashedInputArrayMixin = (superclass) => {
return class extends superclass {
/*
* @summary expects an array with elements containing field [{content: "..."}]
*/
get hashFromArrayInputContent() {
const objectForHashing = this.input.map(i =>
removeEmptyLinesFromString(removeCommentsFromSourceCode(i.content))
);
return calculateHashFromObject(objectForHashing)
}
};
};
65 changes: 65 additions & 0 deletions src/entity/mixins/props.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
export const DefaultableMixin = (superclass) => {
return class extends superclass {
get isDefault() {
return this.prop("isDefault", false);
}

// Define in superclass
// static get defaultConfig() {
// }

static createDefault() {
return new this.prototype.constructor(this.defaultConfig);
}
};
};

export const TaggableMixin = (superclass) => {
return class extends superclass {
get tags() {return this.prop("tags", [])}

set tags(array) {this.setProp("tags", array)}

// only keep unique elements in tags
setTags(array) {this.tags = array.filter((value, index, self) => self.indexOf(value) === index)}
};
};

export const HasMetadataMixin = (superclass) => {
return class extends superclass {
get metadata() {return this.prop("metadata", {})}

set metadata(object) {this.setProp("metadata", object)}

updateMetadata(object) {this.metadata = Object.assign({}, this.metadata, object)}
};
};

export const HasDescriptionMixin = (superclass) => {
return class extends superclass {
get description() {return this.prop("description", "")}

set description(string) {this.setProp("description", string)}

get descriptionObject() {return this.prop("descriptionObject")}

set descriptionObject(obj) {this.setProp("descriptionObject", obj)}
};
};

export const NamedEntityMixin = (superclass) => {
return class extends superclass {
get name() {
return this.prop("name", "");
}

set name(name) {
this.setProp("name", name);
}

// to be used when getter is overriden
setName(name) {
this.setProp("name", name);
}
};
};
28 changes: 28 additions & 0 deletions src/entity/mixins/repetition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const HasRepetitionMixin = (superclass) => {
return class extends superclass {
get repetition() {
return this._repetition || 0
}

setRepetition(repetition) {
this._repetition = repetition;

if (["Subworkflow", "Workflow"].find(n => this.constructor.name === n)) {
this.units.forEach(u => u.setRepetition(repetition));
}

if (this.constructor.name === "Workflow") {
this.subworkflows.forEach(sw => sw.setRepetition(repetition));
this.workflows.forEach(wf => wf.setRepetition(repetition));
}
}

get totalRepetitions() {
return this._totalRepetitions || 1
}

setTotalRepetitions(totalRepetition) {
this._totalRepetitions = totalRepetition;
}
};
};
Loading