Skip to content

Commit d4bebdb

Browse files
authored
Merge pull request #95 from Exabyte-io/chore/SOF-7640
SOF-7640: new ade + fix TaggableMixin usage
2 parents dd6c429 + 4a5a788 commit d4bebdb

File tree

9 files changed

+169
-79
lines changed

9 files changed

+169
-79
lines changed

package-lock.json

Lines changed: 9 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@
4949
"v20": "^0.1.0"
5050
},
5151
"devDependencies": {
52-
"@exabyte-io/ade.js": "2025.7.15-0",
52+
"@exabyte-io/ade.js": "2025.7.15-1",
5353
"@exabyte-io/application-flavors.js": "2025.7.8-0",
5454
"@exabyte-io/eslint-config": "2025.5.13-0",
5555
"@exabyte-io/ide.js": "2024.3.26-0",
5656
"@exabyte-io/mode.js": "2024.4.28-0",
5757
"@mat3ra/code": "2025.7.15-0",
58-
"@mat3ra/esse": "2025.4.26-0",
58+
"@mat3ra/esse": "2025.7.15-0",
5959
"@mat3ra/made": "2025.7.15-0",
6060
"chai": "^4.3.4",
6161
"eslint": "7.32.0",

src/subworkflows/create.js

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Application } from "@exabyte-io/ade.js";
1+
import ApplicationRegistry from "@exabyte-io/ade.js/dist/js/ApplicationRegistry";
22
import {
33
default_methods as MethodConfigs,
44
default_models as ModelConfigs,
@@ -14,17 +14,6 @@ import { workflowData as allWorkflowData } from "../workflows/workflows";
1414
import { dynamicSubworkflowsByApp, getSurfaceEnergySubworkflowUnits } from "./dynamic";
1515
import { Subworkflow } from "./subworkflow";
1616

17-
/**
18-
* @summary Thin wrapper around Application.createFromStored for extensibility
19-
* @param config {Object} application config
20-
* @param applicationCls {any} application class
21-
* @returns {Application} the application
22-
*/
23-
function createApplication({ config, applicationCls }) {
24-
const { name, version, build = "Default" } = config;
25-
return applicationCls.create({ name, version, build });
26-
}
27-
2817
// NOTE: DFTModel => DFTModelConfig, configs should have the same name as the model/method class + "Config" at the end
2918
function _getConfigFromModelOrMethodName(name, kind) {
3019
const configs = kind === "Model" ? ModelConfigs : MethodConfigs;
@@ -63,14 +52,14 @@ function createMethod({ config, methodFactoryCls }) {
6352
/**
6453
* @summary Create top-level objects used in subworkflow initialization
6554
* @param subworkflowData {Object} subworkflow data
66-
* @param applicationCls {any} application class
55+
* @param AppRegistry
6756
* @param modelFactoryCls {any} model factory class
6857
* @param methodFactoryCls {any} method factory class
6958
* @returns {{application: *, method: *, model: (DFTModel|Model), setSearchText: String|null}}
7059
*/
71-
function createTopLevel({ subworkflowData, applicationCls, modelFactoryCls, methodFactoryCls }) {
60+
function createTopLevel({ subworkflowData, modelFactoryCls, methodFactoryCls, AppRegistry }) {
7261
const { application: appConfig, model: modelConfig, method: methodConfig } = subworkflowData;
73-
const application = createApplication({ config: appConfig, applicationCls });
62+
const application = AppRegistry.createApplication(appConfig);
7463
const model = createModel({ config: modelConfig, modelFactoryCls });
7564
const { method, setSearchText } = createMethod({ config: methodConfig, methodFactoryCls });
7665
return {
@@ -91,7 +80,7 @@ function createTopLevel({ subworkflowData, applicationCls, modelFactoryCls, meth
9180
* @param unitFactoryCls {*} workflow unit class factory
9281
* @returns {*|{head: boolean, preProcessors: [], postProcessors: [], name: *, flowchartId: *, type: *, results: [], monitors: []}}
9382
*/
94-
function createUnit({ config, application, unitBuilders, unitFactoryCls }) {
83+
export function createUnit({ config, application, unitBuilders, unitFactoryCls }) {
9584
const { type, config: unitConfig } = config;
9685
if (type === "executionBuilder") {
9786
const { name, execName, flavorName, flowchartId } = unitConfig;
@@ -143,7 +132,7 @@ function createDynamicUnits({
143132

144133
function createSubworkflow({
145134
subworkflowData,
146-
applicationCls = Application,
135+
AppRegistry = ApplicationRegistry,
147136
modelFactoryCls = ModelFactory,
148137
methodFactoryCls = MethodFactory,
149138
subworkflowCls = Subworkflow,
@@ -152,7 +141,7 @@ function createSubworkflow({
152141
}) {
153142
const { application, model, method, setSearchText } = createTopLevel({
154143
subworkflowData,
155-
applicationCls,
144+
AppRegistry,
156145
modelFactoryCls,
157146
methodFactoryCls,
158147
});

src/units/base.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
import {
2-
NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity,
3-
TaggableMixin,
4-
} from "@mat3ra/code/dist/js/entity";
1+
import { NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity } from "@mat3ra/code/dist/js/entity";
2+
import { taggableMixin } from "@mat3ra/code/dist/js/entity/mixins/TaggableMixin";
53
import { getUUID } from "@mat3ra/code/dist/js/utils";
64
import lodash from "lodash";
7-
import { mix } from "mixwith";
85

96
import { UNIT_STATUSES } from "../enums";
107

118
// eslint-disable-next-line max-len
12-
export class BaseUnit extends mix(
13-
NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity,
14-
).with(TaggableMixin) {
9+
export class BaseUnit extends NamedDefaultableRepetitionRuntimeItemsImportantSettingsContextAndRenderHashedInMemoryEntity {
1510
constructor(config) {
1611
super({
1712
...config,
@@ -92,3 +87,5 @@ export class BaseUnit extends mix(
9287
return super.clone(flowchartIDOverrideConfigAsExtraContext);
9388
}
9489
}
90+
91+
taggableMixin(BaseUnit.prototype);
Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
import { Application, Executable, Flavor } from "@exabyte-io/ade.js";
1+
/* eslint-disable class-methods-use-this */
2+
import ApplicationRegistry from "@exabyte-io/ade.js/dist/js/ApplicationRegistry";
23

34
import { UNIT_TYPES } from "../../enums";
45
import { UnitConfigBuilder } from "./UnitConfigBuilder";
56

67
export class ExecutionUnitConfigBuilder extends UnitConfigBuilder {
7-
static Application = Application;
8-
9-
static Executable = Executable;
10-
11-
static Flavor = Flavor;
12-
138
constructor(name, application, execName, flavorName, flowchartId) {
149
super({ name, type: UNIT_TYPES.execution, flowchartId });
1510

@@ -29,14 +24,8 @@ export class ExecutionUnitConfigBuilder extends UnitConfigBuilder {
2924

3025
initialize(application, execName, flavorName) {
3126
this.application = application;
32-
this.executable = this.constructor.Executable.create({
33-
name: execName,
34-
application: this.application,
35-
});
36-
this.flavor = this.constructor.Flavor.create({
37-
name: flavorName,
38-
executable: this.executable,
39-
});
27+
this.executable = this._createExecutable(this.application, execName);
28+
this.flavor = this._createFlavor(this.executable, flavorName);
4029
}
4130

4231
build() {
@@ -47,4 +36,24 @@ export class ExecutionUnitConfigBuilder extends UnitConfigBuilder {
4736
flavor: this.flavor.toJSON(),
4837
};
4938
}
39+
40+
/**
41+
* Creates an executable instance. This method is intended to be overridden in subclasses.
42+
* @param {Application} application - The application object
43+
* @param {string} execName - The name of the executable
44+
* @returns {Executable} The created executable instance
45+
*/
46+
_createExecutable(application, execName) {
47+
return ApplicationRegistry.getExecutableByName(application.name, execName);
48+
}
49+
50+
/**
51+
* Creates a flavor instance. This method is intended to be overridden in subclasses.
52+
* @param {Executable} executable - The executable object
53+
* @param {string} flavorName - The name of the flavor
54+
* @returns {Flavor} The created flavor instance
55+
*/
56+
_createFlavor(executable, flavorName) {
57+
return ApplicationRegistry.getFlavorByName(executable, flavorName);
58+
}
5059
}

src/units/execution.js

Lines changed: 76 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import { Application, Template } from "@exabyte-io/ade.js";
2-
import { HashedInputArrayMixin } from "@mat3ra/code/dist/js/entity";
3-
import { removeTimestampableKeysFromConfig } from "@mat3ra/code/dist/js/utils";
4-
import { mix } from "mixwith";
1+
import { Template } from "@exabyte-io/ade.js";
2+
import ApplicationRegistry from "@exabyte-io/ade.js/dist/js/ApplicationRegistry";
3+
import {
4+
calculateHashFromObject,
5+
removeCommentsFromSourceCode,
6+
removeEmptyLinesFromString,
7+
removeTimestampableKeysFromConfig,
8+
} from "@mat3ra/code/dist/js/utils";
59
import _ from "underscore";
610

711
import { BaseUnit } from "./base";
812

9-
export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) {
10-
static Application = Application;
11-
12-
static Template = Template;
13-
13+
export class ExecutionUnit extends BaseUnit {
1414
// keys to be omitted during toJSON
1515
static omitKeys = [
1616
"job",
@@ -22,18 +22,76 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) {
2222
"hasRelaxation",
2323
];
2424

25+
/**
26+
* @override this method to provide entities from other sources
27+
*/
2528
_initApplication(config) {
26-
this._application = this.constructor.Application.create(config.application);
27-
this._executable = this._application.getExecutableByConfig(config.executable);
28-
this._flavor = this._executable.getFlavorByConfig(config.flavor);
29+
this._application = ApplicationRegistry.createApplication(config.application);
30+
this._executable = ApplicationRegistry.getExecutableByConfig(
31+
this._application.name,
32+
config.executable,
33+
);
34+
this._flavor = ApplicationRegistry.getFlavorByConfig(this._executable, config.flavor);
2935
this._templates = this._flavor ? this._flavor.inputAsTemplates : [];
3036
}
3137

38+
/**
39+
* @override this method to provide default executable from other source
40+
*/
41+
_getDefaultExecutable() {
42+
return ApplicationRegistry.getExecutableByName(this.application.name);
43+
}
44+
45+
/**
46+
* @override this method to provide default flavor from other source
47+
*/
48+
_getDefaultFlavor() {
49+
return ApplicationRegistry.getFlavorByName(this.executable.name);
50+
}
51+
52+
/**
53+
* @override this method to provide custom templates
54+
*/
55+
_getTemplatesFromInput() {
56+
return this.getInput().map((i) => new Template(i));
57+
}
58+
59+
/**
60+
* @override this method to provide custom input from other sources
61+
*/
62+
_getInput() {
63+
return (
64+
this.input ||
65+
ApplicationRegistry.getInputAsRenderedTemplates(
66+
this.flavor,
67+
this.getCombinedContext(),
68+
) ||
69+
[]
70+
);
71+
}
72+
73+
/**
74+
* @override this method to provide custom input as templates
75+
*/
76+
_getInputAsTemplates() {
77+
return ApplicationRegistry.getInputAsTemplates(this.flavor);
78+
}
79+
3280
_initRuntimeItems(keys, config) {
3381
this._initApplication(config);
3482
super._initRuntimeItems(keys);
3583
}
3684

85+
/*
86+
* @summary expects an array with elements containing field [{content: "..."}]
87+
*/
88+
get hashFromArrayInputContent() {
89+
const objectForHashing = this._getInput().map((i) => {
90+
return removeEmptyLinesFromString(removeCommentsFromSourceCode(i.content));
91+
});
92+
return calculateHashFromObject(objectForHashing);
93+
}
94+
3795
get name() {
3896
return this.prop("name", this.flavor.name);
3997
}
@@ -54,29 +112,25 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) {
54112
return this._templates;
55113
}
56114

57-
get templatesFromInput() {
58-
return this.input.map((i) => new this.constructor.Template(i));
59-
}
60-
61115
setApplication(application, omitSettingExecutable = false) {
62116
this._application = application;
63117
this.setProp("application", application.toJSON());
64118
if (!omitSettingExecutable) {
65-
this.setExecutable(this.application.defaultExecutable);
119+
this.setExecutable(this._getDefaultExecutable());
66120
}
67121
}
68122

69123
setExecutable(executable) {
70124
this._executable = executable;
71125
this.setProp("executable", executable.toJSON());
72-
this.setFlavor(this.executable.defaultFlavor);
126+
this.setFlavor(this._getDefaultFlavor());
73127
}
74128

75129
setFlavor(flavor) {
76130
this._flavor = flavor;
77131
this.setRuntimeItemsToDefaultValues();
78132
this.setProp("flavor", flavor.toJSON());
79-
this.setTemplates(this.flavor.inputAsTemplates);
133+
this.setTemplates(this._getInputAsTemplates());
80134
}
81135

82136
setTemplates(templates) {
@@ -126,11 +180,7 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) {
126180
}
127181

128182
get input() {
129-
return (
130-
this.prop("input") ||
131-
this.flavor.getInputAsRenderedTemplates(this.getCombinedContext()) ||
132-
[]
133-
);
183+
return this.prop("input");
134184
}
135185

136186
get renderingContext() {
@@ -167,7 +217,7 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) {
167217
const newRenderingContext = {};
168218
const renderingContext = { ...this.context, ...context };
169219
this.updateContext(renderingContext); // update in-memory context to properly render templates from input below
170-
(fromTemplates ? this.templates : this.templatesFromInput).forEach((t) => {
220+
(fromTemplates ? this.templates : this._getTemplatesFromInput()).forEach((t) => {
171221
newInput.push(t.getRenderedJSON(renderingContext));
172222
Object.assign(
173223
newRenderingContext,
@@ -204,7 +254,7 @@ export class ExecutionUnit extends mix(BaseUnit).with(HashedInputArrayMixin) {
204254
...super.toJSON(),
205255
executable: this.executable.toJSON(),
206256
flavor: this.flavor.toJSON(),
207-
input: this.input,
257+
input: this._getInput(),
208258
// keys below are not propagated to the parent class on initialization of a new unit unless explicitly given
209259
name: this.name,
210260
// TODO: figure out the problem with storing context below

0 commit comments

Comments
 (0)