diff --git a/.nycrc b/.nycrc index 3cd94a5..c8908b6 100644 --- a/.nycrc +++ b/.nycrc @@ -6,6 +6,7 @@ "src/**/*.ts" ], "exclude": [ + "src/js/generated/**/*", "tests/**/*", "**/*.test.ts", "**/*.spec.ts", diff --git a/dist/js/ApplicationRegistry.d.ts b/dist/js/ApplicationRegistry.d.ts index b277021..361db44 100644 --- a/dist/js/ApplicationRegistry.d.ts +++ b/dist/js/ApplicationRegistry.d.ts @@ -1,10 +1,10 @@ -import type { ApplicationSchemaBase } from "@mat3ra/esse/dist/js/types"; -import Application from "./application"; -import Executable from "./executable"; -import Flavor from "./flavor"; -import Template from "./template"; +import type { ApplicationSchema, TemplateSchema } from "@mat3ra/esse/dist/js/types"; +import Application from "./Application"; +import Executable from "./Executable"; +import Flavor from "./Flavor"; +import Template from "./Template"; type ApplicationVersion = { - [build: string]: ApplicationSchemaBase; + [build: string]: ApplicationSchema; }; type ApplicationTreeItem = { defaultVersion: string; @@ -18,7 +18,7 @@ export type CreateApplicationConfig = { type ApplicationTree = Partial>; export default class ApplicationRegistry { static applicationsTree?: ApplicationTree; - static applicationsArray?: ApplicationSchemaBase[]; + static applicationsArray?: ApplicationSchema[]; static createApplication({ name, version, build }: CreateApplicationConfig): Application; static getUniqueAvailableApplicationNames(): string[]; /** @@ -27,7 +27,7 @@ export default class ApplicationRegistry { */ static getAllApplications(): { applicationsTree: Partial>; - applicationsArray: ApplicationSchemaBase[]; + applicationsArray: ApplicationSchema[]; }; /** * @summary Get an application from the constructed applications @@ -36,7 +36,7 @@ export default class ApplicationRegistry { * @param build the build to use (optional, defaults to Default) * @return an application */ - static getApplicationConfig({ name, version, build }: CreateApplicationConfig): ApplicationSchemaBase | null; + static getApplicationConfig({ name, version, build }: CreateApplicationConfig): ApplicationSchema | null; static getExecutables({ name, version }: { name: string; version?: string; @@ -51,7 +51,7 @@ export default class ApplicationRegistry { name: string; }): Flavor | undefined; static getInputAsTemplates(flavor: Flavor): Template[]; - static getInputAsRenderedTemplates(flavor: Flavor, context: Record): import("@mat3ra/esse/dist/js/esse/types").AnyObject[]; + static getInput(flavor: Flavor): TemplateSchema[]; static getAllFlavorsForApplication(appName: string, version?: string): Flavor[]; } export {}; diff --git a/dist/js/ApplicationRegistry.js b/dist/js/ApplicationRegistry.js index 7afe7e0..b2fe069 100644 --- a/dist/js/ApplicationRegistry.js +++ b/dist/js/ApplicationRegistry.js @@ -5,14 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); const object_1 = require("@mat3ra/code/dist/js/utils/object"); const standata_1 = require("@mat3ra/standata"); -const application_1 = __importDefault(require("./application")); -const executable_1 = __importDefault(require("./executable")); -const flavor_1 = __importDefault(require("./flavor")); -const template_1 = __importDefault(require("./template")); +const Application_1 = __importDefault(require("./Application")); +const Executable_1 = __importDefault(require("./Executable")); +const Flavor_1 = __importDefault(require("./Flavor")); +const Template_1 = __importDefault(require("./Template")); class ApplicationRegistry { static createApplication({ name, version = null, build = null }) { const staticConfig = ApplicationRegistry.getApplicationConfig({ name, version, build }); - return new application_1.default({ + return new Application_1.default({ ...staticConfig, name, ...(version && { version }), @@ -52,6 +52,7 @@ class ApplicationRegistry { appTreeItem[version] = appVersion; const applicationConfig = { ...appData, + // @ts-ignore build: buildToUse, ...versionInfo, }; @@ -114,7 +115,7 @@ class ApplicationRegistry { return (!supportedApplicationVersions || (version && supportedApplicationVersions.includes(version))); }) - .map((key) => new executable_1.default({ ...tree[key], name: key })); + .map((key) => new Executable_1.default({ ...tree[key], name: key })); } static getExecutableByName(appName, execName) { const appTree = new standata_1.ApplicationStandata().getAppTreeForApplication(appName); @@ -124,7 +125,7 @@ class ApplicationRegistry { const config = execName ? appTree[execName] : (0, object_1.getOneMatchFromObject)(appTree, "isDefault", true); - return new executable_1.default(config); + return new Executable_1.default(config); } // TODO: remove this method and use getApplicationExecutableByName directly static getExecutableByConfig(appName, config) { @@ -133,7 +134,7 @@ class ApplicationRegistry { static getExecutableFlavors(executable) { const flavorsTree = executable.prop("flavors", {}); return Object.keys(flavorsTree).map((key) => { - return new flavor_1.default({ + return new Flavor_1.default({ ...flavorsTree[key], name: key, }); @@ -145,24 +146,26 @@ class ApplicationRegistry { static getFlavorByConfig(executable, config) { return this.getFlavorByName(executable, config === null || config === void 0 ? void 0 : config.name); } - // flavors static getInputAsTemplates(flavor) { - const appName = flavor.prop("applicationName", ""); - const execName = flavor.prop("executableName", ""); + return this.getInput(flavor).map((template) => new Template_1.default(template)); + } + static getInput(flavor) { + const appName = flavor.applicationName || ""; + const execName = flavor.executableName || ""; return flavor.input.map((input) => { const inputName = input.templateName || input.name; const filtered = new standata_1.ApplicationStandata().getTemplatesByName(appName, execName, inputName); if (filtered.length !== 1) { console.log(`found ${filtered.length} templates for app=${appName} exec=${execName} name=${inputName} expected 1`); } - return new template_1.default({ ...filtered[0], name: input.name }); - }); - } - static getInputAsRenderedTemplates(flavor, context) { - return this.getInputAsTemplates(flavor).map((template) => { - return template.getRenderedJSON(context); + return { ...filtered[0], name: input.name || "" }; }); } + // static getInputAsRenderedTemplates(flavor: Flavor, context: ContextProviderConfig) { + // return this.getInputAsTemplates(flavor).map((template) => { + // return template.setContext(context).render().toJSON(); + // }); + // } static getAllFlavorsForApplication(appName, version) { const allExecutables = this.getExecutables({ name: appName, version }); return allExecutables.flatMap((executable) => this.getExecutableFlavors(executable)); diff --git a/dist/js/application.d.ts b/dist/js/application.d.ts index fd78625..2131e0f 100644 --- a/dist/js/application.d.ts +++ b/dist/js/application.d.ts @@ -1,8 +1,13 @@ -import { NamedDefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { type DefaultableInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import { type NamedInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { ApplicationSchema } from "@mat3ra/esse/dist/js/types"; import { type ApplicationMixin, type ApplicationStaticMixin } from "./applicationMixin"; -type Base = typeof NamedDefaultableInMemoryEntity & Constructor & ApplicationStaticMixin; +type Base = typeof InMemoryEntity & NamedInMemoryEntityConstructor & DefaultableInMemoryEntityConstructor & Constructor & ApplicationStaticMixin; declare const Application_base: Base; -export default class Application extends Application_base { +export default class Application extends Application_base implements ApplicationSchema { + constructor(data?: Partial); + static createDefault: () => Application; } export {}; diff --git a/dist/js/application.js b/dist/js/application.js index 129810e..8f344d9 100644 --- a/dist/js/application.js +++ b/dist/js/application.js @@ -1,9 +1,17 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const entity_1 = require("@mat3ra/code/dist/js/entity"); +const DefaultableMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"); +const NamedEntityMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"); const applicationMixin_1 = require("./applicationMixin"); -class Application extends entity_1.NamedDefaultableInMemoryEntity { +class Application extends entity_1.InMemoryEntity { + constructor(data = {}) { + super({ + ...data, + }); + } } exports.default = Application; -(0, applicationMixin_1.applicationMixin)(Application.prototype); -(0, applicationMixin_1.applicationStaticMixin)(Application); +(0, NamedEntityMixin_1.namedEntityMixin)(Application.prototype); +(0, DefaultableMixin_1.defaultableEntityMixin)(Application); +(0, applicationMixin_1.applicationMixin)(Application); diff --git a/dist/js/applicationMixin.d.ts b/dist/js/applicationMixin.d.ts index 11aab73..621e752 100644 --- a/dist/js/applicationMixin.d.ts +++ b/dist/js/applicationMixin.d.ts @@ -1,23 +1,22 @@ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { DefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; -import type { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import type { Defaultable } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import type { NamedEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; -import type { ApplicationSchemaBase } from "@mat3ra/esse/dist/js/types"; -import Executable from "./executable"; -type Base = InMemoryEntity & NamedInMemoryEntity & DefaultableInMemoryEntity; +import type { ApplicationSchema } from "@mat3ra/esse/dist/js/types"; +import Executable from "./Executable"; +import { type ApplicationSchemaMixin } from "./generated/ApplicationSchemaMixin"; +type Base = InMemoryEntity & NamedEntity & Defaultable; export type BaseConstructor = Constructor & { constructCustomExecutable?: (config: object) => Executable; }; -export type ApplicationConstructor = Constructor & ApplicationStaticMixin; -export type ApplicationMixin = Pick & { - name: Required["name"]; +export type ApplicationMixin = ApplicationSchemaMixin & { + name: Required["name"]; isUsingMaterial: boolean; }; -export type DefaultApplicationConfig = Pick; +export type DefaultApplicationConfig = Pick; export type ApplicationStaticMixin = { defaultConfig: DefaultApplicationConfig; - jsonSchema: ApplicationSchemaBase; + jsonSchema: ApplicationSchema; }; -export declare function applicationMixin(item: Base): void; -export declare function applicationStaticMixin(Application: T): void; +export declare function applicationMixin(Item: BaseConstructor): void; export {}; diff --git a/dist/js/applicationMixin.js b/dist/js/applicationMixin.js index 7d7945f..11ed596 100644 --- a/dist/js/applicationMixin.js +++ b/dist/js/applicationMixin.js @@ -4,30 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.applicationMixin = applicationMixin; -exports.applicationStaticMixin = applicationStaticMixin; const JSONSchemasInterface_1 = __importDefault(require("@mat3ra/esse/dist/js/esse/JSONSchemasInterface")); const standata_1 = require("@mat3ra/standata"); -function applicationMixin(item) { +const ApplicationSchemaMixin_1 = require("./generated/ApplicationSchemaMixin"); +function applicationPropertiesMixin(item) { // @ts-expect-error const properties = { - get summary() { - return this.prop("summary"); - }, - get version() { - return this.prop("version", ""); - }, - get build() { - return this.prop("build"); - }, - get shortName() { - return this.prop("shortName", this.name); - }, - get hasAdvancedComputeOptions() { - return this.prop("hasAdvancedComputeOptions", false); - }, - get isLicensed() { - return this.prop("isLicensed", false); - }, get isUsingMaterial() { const materialUsingApplications = ["vasp", "nwchem", "espresso"]; return materialUsingApplications.includes(this.name); @@ -46,3 +28,8 @@ function applicationStaticMixin(Application) { }; Object.defineProperties(Application, Object.getOwnPropertyDescriptors(properties)); } +function applicationMixin(Item) { + (0, ApplicationSchemaMixin_1.applicationSchemaMixin)(Item.prototype); + applicationPropertiesMixin(Item.prototype); + applicationStaticMixin(Item); +} diff --git a/dist/js/context/ContextProviderJinja.d.ts b/dist/js/context/ContextProviderJinja.d.ts deleted file mode 100644 index 75cade4..0000000 --- a/dist/js/context/ContextProviderJinja.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ContextProviderSchema } from "@mat3ra/esse/dist/js/types"; -import ContextProvider from "./ContextProvider"; -interface JSONSchemaDataProviderConfig extends ContextProviderSchema { - isUsingJinjaVariables?: boolean; -} -export default class ContextProviderJinja extends ContextProvider { - isUsingJinjaVariables: boolean; - constructor(config: JSONSchemaDataProviderConfig); -} -export {}; diff --git a/dist/js/context/ContextProviderJinja.js b/dist/js/context/ContextProviderJinja.js deleted file mode 100644 index 61c41f8..0000000 --- a/dist/js/context/ContextProviderJinja.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const ContextProvider_1 = __importDefault(require("./ContextProvider")); -class ContextProviderJinja extends ContextProvider_1.default { - constructor(config) { - super(config); - this.isUsingJinjaVariables = Boolean(config.isUsingJinjaVariables); - } -} -exports.default = ContextProviderJinja; diff --git a/dist/js/context/JSONSchemaDataProvider.d.ts b/dist/js/context/JSONSchemaDataProvider.d.ts deleted file mode 100644 index 30f033f..0000000 --- a/dist/js/context/JSONSchemaDataProvider.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import JinjaContextProvider from "./JinjaContextProvider"; -/** - * @summary Provides jsonSchema only. - */ -export default class JSONSchemaDataProvider extends JinjaContextProvider { - get jsonSchema(): void; -} diff --git a/dist/js/context/JSONSchemaDataProvider.js b/dist/js/context/JSONSchemaDataProvider.js deleted file mode 100644 index 6f2c8bf..0000000 --- a/dist/js/context/JSONSchemaDataProvider.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -/* eslint-disable class-methods-use-this */ -const JinjaContextProvider_1 = __importDefault(require("./JinjaContextProvider")); -/** - * @summary Provides jsonSchema only. - */ -class JSONSchemaDataProvider extends JinjaContextProvider_1.default { - get jsonSchema() { - throw new Error("Not implemented."); - } -} -exports.default = JSONSchemaDataProvider; diff --git a/dist/js/context/JSONSchemaFormDataProvider.d.ts b/dist/js/context/JSONSchemaFormDataProvider.d.ts deleted file mode 100644 index 349ad61..0000000 --- a/dist/js/context/JSONSchemaFormDataProvider.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { UiSchema } from "react-jsonschema-form"; -import JSONSchemaDataProvider from "./JSONSchemaDataProvider"; -/** - * @summary Provides jsonSchema and uiSchema for generating react-jsonschema-form - * See https://github.com/mozilla-services/react-jsonschema-form for Form UI. - * Form generation example: - * ``` - *
- * ``` - */ -export default class JSONSchemaFormDataProvider extends JSONSchemaDataProvider { - get uiSchema(): UiSchema; - get fields(): {}; - get defaultFieldStyles(): {}; - get uiSchemaStyled(): UiSchema; -} diff --git a/dist/js/context/JSONSchemaFormDataProvider.js b/dist/js/context/JSONSchemaFormDataProvider.js deleted file mode 100644 index e9454a2..0000000 --- a/dist/js/context/JSONSchemaFormDataProvider.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const JSONSchemaDataProvider_1 = __importDefault(require("./JSONSchemaDataProvider")); -/** - * @summary Provides jsonSchema and uiSchema for generating react-jsonschema-form - * See https://github.com/mozilla-services/react-jsonschema-form for Form UI. - * Form generation example: - * ``` - * - * ``` - */ -// TODO: MOVE to WebApp/ave or wove -class JSONSchemaFormDataProvider extends JSONSchemaDataProvider_1.default { - get uiSchema() { - throw new Error("Not implemented."); - } - get fields() { - return {}; - } - get defaultFieldStyles() { - return {}; - } - get uiSchemaStyled() { - const schema = this.uiSchema; - return Object.fromEntries(Object.entries(schema).map(([key, value]) => [ - key, - { - ...value, - ...this.defaultFieldStyles, - classNames: `${value.classNames || ""}`, - }, - ])); - } -} -exports.default = JSONSchemaFormDataProvider; diff --git a/dist/js/context/JinjaContextProvider.d.ts b/dist/js/context/JinjaContextProvider.d.ts deleted file mode 100644 index 68f0f86..0000000 --- a/dist/js/context/JinjaContextProvider.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ContextProviderSchema } from "@mat3ra/esse/dist/js/types"; -import ContextProvider from "./ContextProvider"; -interface JSONSchemaDataProviderConfig extends ContextProviderSchema { - isUsingJinjaVariables?: boolean; -} -export default class JinjaContextProvider extends ContextProvider { - isUsingJinjaVariables: boolean; - constructor(config: JSONSchemaDataProviderConfig); -} -export {}; diff --git a/dist/js/context/JinjaContextProvider.js b/dist/js/context/JinjaContextProvider.js deleted file mode 100644 index d0adbb2..0000000 --- a/dist/js/context/JinjaContextProvider.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const ContextProvider_1 = __importDefault(require("./ContextProvider")); -class JinjaContextProvider extends ContextProvider_1.default { - constructor(config) { - super(config); - this.isUsingJinjaVariables = Boolean(config.isUsingJinjaVariables); - } -} -exports.default = JinjaContextProvider; diff --git a/dist/js/executable.d.ts b/dist/js/executable.d.ts index 4f521d3..3777e58 100644 --- a/dist/js/executable.d.ts +++ b/dist/js/executable.d.ts @@ -1,8 +1,14 @@ -import { NamedDefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { type DefaultableInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import { type NamedInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import { type RuntimeItemsInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { ExecutableSchema } from "@mat3ra/esse/dist/js/types"; import { type ExecutableMixin } from "./executableMixin"; -type Base = Constructor & typeof NamedDefaultableInMemoryEntity; +type Base = Constructor & RuntimeItemsInMemoryEntityConstructor & NamedInMemoryEntityConstructor & DefaultableInMemoryEntityConstructor & typeof InMemoryEntity; declare const Executable_base: Base; -export default class Executable extends Executable_base { +export default class Executable extends Executable_base implements ExecutableSchema { + constructor(data?: Partial); + static createDefault: () => Executable; } export {}; diff --git a/dist/js/executable.js b/dist/js/executable.js index 878cfaa..161a8d6 100644 --- a/dist/js/executable.js +++ b/dist/js/executable.js @@ -1,12 +1,24 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const entity_1 = require("@mat3ra/code/dist/js/entity"); +const DefaultableMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"); +const NamedEntityMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"); const RuntimeItemsMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"); const executableMixin_1 = require("./executableMixin"); -class Executable extends entity_1.NamedDefaultableInMemoryEntity { +class Executable extends entity_1.InMemoryEntity { + constructor(data = {}) { + super({ + monitors: [], + results: [], + postProcessors: [], + preProcessors: [], + applicationId: [], + ...data, + }); + } } exports.default = Executable; -// Apply mixins +(0, NamedEntityMixin_1.namedEntityMixin)(Executable.prototype); +(0, DefaultableMixin_1.defaultableEntityMixin)(Executable); (0, RuntimeItemsMixin_1.runtimeItemsMixin)(Executable.prototype); -(0, executableMixin_1.executableMixin)(Executable.prototype); -(0, executableMixin_1.executableStaticMixin)(Executable); +(0, executableMixin_1.executableMixin)(Executable); diff --git a/dist/js/executableMixin.d.ts b/dist/js/executableMixin.d.ts index 87b9d2a..aa8f597 100644 --- a/dist/js/executableMixin.d.ts +++ b/dist/js/executableMixin.d.ts @@ -1,22 +1,21 @@ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { DefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; -import type { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import type { Defaultable } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import type { NamedEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; import type { ExecutableSchema } from "@mat3ra/esse/dist/js/types"; import type { FlavorMixin } from "./flavorMixin"; -type BaseFlavor = FlavorMixin & NamedInMemoryEntity & InMemoryEntity; -type Base = InMemoryEntity & NamedInMemoryEntity & DefaultableInMemoryEntity; -export declare function executableMixin(item: Base): void; -export declare function executableStaticMixin(Executable: Constructor): void; +import { ExecutableSchemaMixin } from "./generated/ExecutableSchemaMixin"; +type BaseFlavor = FlavorMixin & NamedEntity & InMemoryEntity; +type Base = InMemoryEntity & NamedEntity & Defaultable; export type BaseConstructor = Constructor & { constructCustomFlavor?: (config: object) => BaseFlavor; }; -export type ExecutableMixin = { - applicationId: string[]; +export type ExecutableMixin = ExecutableSchemaMixin & { toJSON: () => ExecutableSchema & AnyObject; }; export type ExecutableStaticMixin = { jsonSchema: ExecutableSchema; }; +export declare function executableMixin(Item: BaseConstructor): void; export {}; diff --git a/dist/js/executableMixin.js b/dist/js/executableMixin.js index bf3169d..eff4125 100644 --- a/dist/js/executableMixin.js +++ b/dist/js/executableMixin.js @@ -4,20 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.executableMixin = executableMixin; -exports.executableStaticMixin = executableStaticMixin; const JSONSchemasInterface_1 = __importDefault(require("@mat3ra/esse/dist/js/esse/JSONSchemasInterface")); -function executableMixin(item) { - // @ts-expect-error - const properties = { - get applicationId() { - return this.prop("applicationId", []); - }, - set applicationId(value) { - this.setProp("applicationId", value); - }, - }; - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} +const ExecutableSchemaMixin_1 = require("./generated/ExecutableSchemaMixin"); function executableStaticMixin(Executable) { const properties = { get jsonSchema() { @@ -26,3 +14,7 @@ function executableStaticMixin(Executable) { }; Object.defineProperties(Executable, Object.getOwnPropertyDescriptors(properties)); } +function executableMixin(Item) { + (0, ExecutableSchemaMixin_1.executableSchemaMixin)(Item.prototype); + executableStaticMixin(Item); +} diff --git a/dist/js/flavor.d.ts b/dist/js/flavor.d.ts index 4134aff..f6f4285 100644 --- a/dist/js/flavor.d.ts +++ b/dist/js/flavor.d.ts @@ -1,9 +1,14 @@ -import { NamedDefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import { type RuntimeItemsInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { type DefaultableInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import { NamedInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import { type RuntimeItemsInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { FlavorSchema } from "@mat3ra/esse/dist/js/types"; import { type FlavorMixin } from "./flavorMixin"; -type Base = typeof NamedDefaultableInMemoryEntity & Constructor & Constructor; +type Base = typeof InMemoryEntity & Constructor & RuntimeItemsInMemoryEntityConstructor & NamedInMemoryEntityConstructor & DefaultableInMemoryEntityConstructor; declare const Flavor_base: Base; -export default class Flavor extends Flavor_base { +export default class Flavor extends Flavor_base implements FlavorSchema { + constructor(data?: Partial); + static createDefault: () => Flavor; } export {}; diff --git a/dist/js/flavor.js b/dist/js/flavor.js index 956e74c..ed31a4f 100644 --- a/dist/js/flavor.js +++ b/dist/js/flavor.js @@ -1,12 +1,27 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const entity_1 = require("@mat3ra/code/dist/js/entity"); +const DefaultableMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"); +const NamedEntityMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"); const RuntimeItemsMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"); const flavorMixin_1 = require("./flavorMixin"); -class Flavor extends entity_1.NamedDefaultableInMemoryEntity { +class Flavor extends entity_1.InMemoryEntity { + constructor(data = {}) { + super({ + monitors: [], + results: [], + postProcessors: [], + preProcessors: [], + input: [], + executableId: "", + executableName: "", + applicationName: "", + ...data, + }); + } } exports.default = Flavor; -// Apply mixins -(0, flavorMixin_1.flavorMixin)(Flavor.prototype); +(0, NamedEntityMixin_1.namedEntityMixin)(Flavor.prototype); +(0, DefaultableMixin_1.defaultableEntityMixin)(Flavor); (0, RuntimeItemsMixin_1.runtimeItemsMixin)(Flavor.prototype); -(0, flavorMixin_1.flavorStaticMixin)(Flavor); +(0, flavorMixin_1.flavorMixin)(Flavor); diff --git a/dist/js/flavorMixin.d.ts b/dist/js/flavorMixin.d.ts index 3c42e3d..117baab 100644 --- a/dist/js/flavorMixin.d.ts +++ b/dist/js/flavorMixin.d.ts @@ -1,21 +1,9 @@ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; import type { FlavorSchema } from "@mat3ra/esse/dist/js/types"; -type Base = InMemoryEntity & NamedInMemoryEntity; -type Input = Required["input"]; -export type FlavorMixin = { - input: Input; - disableRenderMaterials: boolean; - executableId: string; - executableName: string; - applicationName: string; - supportedApplicationVersions?: string[]; - getInputAsRenderedTemplates: (context: Record) => Record[]; -}; -export declare function flavorMixin(item: Base): FlavorMixin & InMemoryEntity & NamedInMemoryEntity; -export declare function flavorStaticMixin(Flavor: Constructor): void; +import { type FlavorSchemaMixin } from "./generated/FlavorSchemaMixin"; +export type FlavorMixin = FlavorSchemaMixin; export type FlavorStaticMixin = { jsonSchema: FlavorSchema; }; -export {}; +export declare function flavorMixin(Item: Constructor): void; diff --git a/dist/js/flavorMixin.js b/dist/js/flavorMixin.js index c771bf7..96fa3ca 100644 --- a/dist/js/flavorMixin.js +++ b/dist/js/flavorMixin.js @@ -4,43 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.flavorMixin = flavorMixin; -exports.flavorStaticMixin = flavorStaticMixin; const JSONSchemasInterface_1 = __importDefault(require("@mat3ra/esse/dist/js/esse/JSONSchemasInterface")); -// TODO: should we add fields from esse schema (executableId, executableName, applicationName)? -function flavorMixin(item) { - // @ts-expect-error - const properties = { - get input() { - return this.prop("input", []); - }, - get disableRenderMaterials() { - return this.prop("isMultiMaterial", false); - }, - get executableId() { - return this.prop("executableId", ""); - }, - get executableName() { - return this.prop("executableName", ""); - }, - get applicationName() { - return this.prop("applicationName", ""); - }, - get supportedApplicationVersions() { - return this.prop("supportedApplicationVersions"); - }, - getInputAsRenderedTemplates(context) { - const input = this.input; - return input.map((template) => { - if (template && typeof template === "object" && "getRenderedJSON" in template) { - return template.getRenderedJSON(context); - } - return template; - }); - }, - }; - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); - return properties; -} +const FlavorSchemaMixin_1 = require("./generated/FlavorSchemaMixin"); function flavorStaticMixin(Flavor) { const properties = { get jsonSchema() { @@ -49,3 +14,7 @@ function flavorStaticMixin(Flavor) { }; Object.defineProperties(Flavor, Object.getOwnPropertyDescriptors(properties)); } +function flavorMixin(Item) { + (0, FlavorSchemaMixin_1.flavorSchemaMixin)(Item.prototype); + flavorStaticMixin(Item); +} diff --git a/dist/js/generated/ApplicationSchemaMixin.d.ts b/dist/js/generated/ApplicationSchemaMixin.d.ts new file mode 100644 index 0000000..11fd11a --- /dev/null +++ b/dist/js/generated/ApplicationSchemaMixin.d.ts @@ -0,0 +1,5 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ApplicationPropertiesSchema } from "@mat3ra/esse/dist/js/types"; +export type ApplicationSchemaMixin = ApplicationPropertiesSchema; +export type ApplicationInMemoryEntity = InMemoryEntity & ApplicationSchemaMixin; +export declare function applicationSchemaMixin(item: InMemoryEntity): asserts item is T & ApplicationSchemaMixin; diff --git a/dist/js/generated/ApplicationSchemaMixin.js b/dist/js/generated/ApplicationSchemaMixin.js new file mode 100644 index 0000000..63a8df0 --- /dev/null +++ b/dist/js/generated/ApplicationSchemaMixin.js @@ -0,0 +1,45 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.applicationSchemaMixin = applicationSchemaMixin; +function applicationSchemaMixin(item) { + // @ts-expect-error + const properties = { + get shortName() { + return this.requiredProp("shortName"); + }, + set shortName(value) { + this.setProp("shortName", value); + }, + get summary() { + return this.requiredProp("summary"); + }, + set summary(value) { + this.setProp("summary", value); + }, + get version() { + return this.requiredProp("version"); + }, + set version(value) { + this.setProp("version", value); + }, + get build() { + return this.requiredProp("build"); + }, + set build(value) { + this.setProp("build", value); + }, + get hasAdvancedComputeOptions() { + return this.prop("hasAdvancedComputeOptions"); + }, + set hasAdvancedComputeOptions(value) { + this.setProp("hasAdvancedComputeOptions", value); + }, + get isLicensed() { + return this.prop("isLicensed"); + }, + set isLicensed(value) { + this.setProp("isLicensed", value); + }, + }; + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/dist/js/generated/ExecutableSchemaMixin.d.ts b/dist/js/generated/ExecutableSchemaMixin.d.ts new file mode 100644 index 0000000..11f70b8 --- /dev/null +++ b/dist/js/generated/ExecutableSchemaMixin.d.ts @@ -0,0 +1,5 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ExecutablePropertiesSchema } from "@mat3ra/esse/dist/js/types"; +export type ExecutableSchemaMixin = ExecutablePropertiesSchema; +export type ExecutableInMemoryEntity = InMemoryEntity & ExecutableSchemaMixin; +export declare function executableSchemaMixin(item: InMemoryEntity): asserts item is T & ExecutableSchemaMixin; diff --git a/dist/js/generated/ExecutableSchemaMixin.js b/dist/js/generated/ExecutableSchemaMixin.js new file mode 100644 index 0000000..6ab21d3 --- /dev/null +++ b/dist/js/generated/ExecutableSchemaMixin.js @@ -0,0 +1,27 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.executableSchemaMixin = executableSchemaMixin; +function executableSchemaMixin(item) { + // @ts-expect-error + const properties = { + get name() { + return this.requiredProp("name"); + }, + set name(value) { + this.setProp("name", value); + }, + get applicationId() { + return this.requiredProp("applicationId"); + }, + set applicationId(value) { + this.setProp("applicationId", value); + }, + get hasAdvancedComputeOptions() { + return this.prop("hasAdvancedComputeOptions"); + }, + set hasAdvancedComputeOptions(value) { + this.setProp("hasAdvancedComputeOptions", value); + }, + }; + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/dist/js/generated/FlavorSchemaMixin.d.ts b/dist/js/generated/FlavorSchemaMixin.d.ts new file mode 100644 index 0000000..c239783 --- /dev/null +++ b/dist/js/generated/FlavorSchemaMixin.d.ts @@ -0,0 +1,5 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { FlavorPropertiesSchema } from "@mat3ra/esse/dist/js/types"; +export type FlavorSchemaMixin = FlavorPropertiesSchema; +export type FlavorInMemoryEntity = InMemoryEntity & FlavorSchemaMixin; +export declare function flavorSchemaMixin(item: InMemoryEntity): asserts item is T & FlavorSchemaMixin; diff --git a/dist/js/generated/FlavorSchemaMixin.js b/dist/js/generated/FlavorSchemaMixin.js new file mode 100644 index 0000000..cf3434f --- /dev/null +++ b/dist/js/generated/FlavorSchemaMixin.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.flavorSchemaMixin = flavorSchemaMixin; +function flavorSchemaMixin(item) { + // @ts-expect-error + const properties = { + get executableId() { + return this.requiredProp("executableId"); + }, + set executableId(value) { + this.setProp("executableId", value); + }, + get executableName() { + return this.prop("executableName"); + }, + set executableName(value) { + this.setProp("executableName", value); + }, + get applicationName() { + return this.prop("applicationName"); + }, + set applicationName(value) { + this.setProp("applicationName", value); + }, + get input() { + return this.requiredProp("input"); + }, + set input(value) { + this.setProp("input", value); + }, + get supportedApplicationVersions() { + return this.prop("supportedApplicationVersions"); + }, + set supportedApplicationVersions(value) { + this.setProp("supportedApplicationVersions", value); + }, + }; + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/dist/js/generated/TemplateSchemaMixin.d.ts b/dist/js/generated/TemplateSchemaMixin.d.ts new file mode 100644 index 0000000..0c81a08 --- /dev/null +++ b/dist/js/generated/TemplateSchemaMixin.d.ts @@ -0,0 +1,5 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { TemplatePropertiesSchema } from "@mat3ra/esse/dist/js/types"; +export type TemplateSchemaMixin = TemplatePropertiesSchema; +export type TemplateInMemoryEntity = InMemoryEntity & TemplateSchemaMixin; +export declare function templateSchemaMixin(item: InMemoryEntity): asserts item is T & TemplateSchemaMixin; diff --git a/dist/js/generated/TemplateSchemaMixin.js b/dist/js/generated/TemplateSchemaMixin.js new file mode 100644 index 0000000..b9c0916 --- /dev/null +++ b/dist/js/generated/TemplateSchemaMixin.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.templateSchemaMixin = templateSchemaMixin; +function templateSchemaMixin(item) { + // @ts-expect-error + const properties = { + get applicationName() { + return this.requiredProp("applicationName"); + }, + set applicationName(value) { + this.setProp("applicationName", value); + }, + get applicationVersion() { + return this.prop("applicationVersion"); + }, + set applicationVersion(value) { + this.setProp("applicationVersion", value); + }, + get executableName() { + return this.requiredProp("executableName"); + }, + set executableName(value) { + this.setProp("executableName", value); + }, + get contextProviders() { + return this.requiredProp("contextProviders"); + }, + set contextProviders(value) { + this.setProp("contextProviders", value); + }, + get content() { + return this.requiredProp("content"); + }, + set content(value) { + this.setProp("content", value); + }, + }; + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/dist/js/index.d.ts b/dist/js/index.d.ts index fdf3a18..dcaa237 100644 --- a/dist/js/index.d.ts +++ b/dist/js/index.d.ts @@ -1,14 +1,12 @@ -import Application from "./application"; -import { applicationMixin, applicationStaticMixin } from "./applicationMixin"; +import Application from "./Application"; +import { applicationMixin } from "./applicationMixin"; import ApplicationRegistry from "./ApplicationRegistry"; -import ContextProvider from "./context/ContextProvider"; -import JSONSchemaFormDataProvider from "./context/JSONSchemaFormDataProvider"; -import Executable from "./executable"; +import Executable from "./Executable"; import { executableMixin } from "./executableMixin"; -import Flavor from "./flavor"; +import Flavor from "./Flavor"; import { flavorMixin } from "./flavorMixin"; -import Template from "./template"; -import { templateMixin, templateStaticMixin } from "./templateMixin"; +import Template from "./Template"; +import { templateMixin } from "./templateMixin"; declare const allApplications: string[]; -export { Application, Executable, Flavor, Template, ApplicationRegistry, ContextProvider, JSONSchemaFormDataProvider, executableMixin, flavorMixin, applicationMixin, applicationStaticMixin, templateMixin, templateStaticMixin, allApplications, }; +export { Application, Executable, Flavor, Template, ApplicationRegistry, executableMixin, flavorMixin, applicationMixin, templateMixin, allApplications, }; export type * from "./types"; diff --git a/dist/js/index.js b/dist/js/index.js index 58497ad..90d6fee 100644 --- a/dist/js/index.js +++ b/dist/js/index.js @@ -3,30 +3,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.allApplications = exports.templateStaticMixin = exports.templateMixin = exports.applicationStaticMixin = exports.applicationMixin = exports.flavorMixin = exports.executableMixin = exports.JSONSchemaFormDataProvider = exports.ContextProvider = exports.ApplicationRegistry = exports.Template = exports.Flavor = exports.Executable = exports.Application = void 0; -const application_1 = __importDefault(require("./application")); -exports.Application = application_1.default; +exports.allApplications = exports.templateMixin = exports.applicationMixin = exports.flavorMixin = exports.executableMixin = exports.ApplicationRegistry = exports.Template = exports.Flavor = exports.Executable = exports.Application = void 0; +const Application_1 = __importDefault(require("./Application")); +exports.Application = Application_1.default; const applicationMixin_1 = require("./applicationMixin"); Object.defineProperty(exports, "applicationMixin", { enumerable: true, get: function () { return applicationMixin_1.applicationMixin; } }); -Object.defineProperty(exports, "applicationStaticMixin", { enumerable: true, get: function () { return applicationMixin_1.applicationStaticMixin; } }); const ApplicationRegistry_1 = __importDefault(require("./ApplicationRegistry")); exports.ApplicationRegistry = ApplicationRegistry_1.default; -const ContextProvider_1 = __importDefault(require("./context/ContextProvider")); -exports.ContextProvider = ContextProvider_1.default; -const JSONSchemaFormDataProvider_1 = __importDefault(require("./context/JSONSchemaFormDataProvider")); -exports.JSONSchemaFormDataProvider = JSONSchemaFormDataProvider_1.default; -const executable_1 = __importDefault(require("./executable")); -exports.Executable = executable_1.default; +const Executable_1 = __importDefault(require("./Executable")); +exports.Executable = Executable_1.default; const executableMixin_1 = require("./executableMixin"); Object.defineProperty(exports, "executableMixin", { enumerable: true, get: function () { return executableMixin_1.executableMixin; } }); -const flavor_1 = __importDefault(require("./flavor")); -exports.Flavor = flavor_1.default; +const Flavor_1 = __importDefault(require("./Flavor")); +exports.Flavor = Flavor_1.default; const flavorMixin_1 = require("./flavorMixin"); Object.defineProperty(exports, "flavorMixin", { enumerable: true, get: function () { return flavorMixin_1.flavorMixin; } }); -const template_1 = __importDefault(require("./template")); -exports.Template = template_1.default; +const Template_1 = __importDefault(require("./Template")); +exports.Template = Template_1.default; const templateMixin_1 = require("./templateMixin"); Object.defineProperty(exports, "templateMixin", { enumerable: true, get: function () { return templateMixin_1.templateMixin; } }); -Object.defineProperty(exports, "templateStaticMixin", { enumerable: true, get: function () { return templateMixin_1.templateStaticMixin; } }); const allApplications = ApplicationRegistry_1.default.getUniqueAvailableApplicationNames(); exports.allApplications = allApplications; diff --git a/dist/js/template.d.ts b/dist/js/template.d.ts index f507f98..0c7be83 100644 --- a/dist/js/template.d.ts +++ b/dist/js/template.d.ts @@ -1,8 +1,11 @@ -import { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { type NamedInMemoryEntityConstructor } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { TemplateSchema } from "@mat3ra/esse/dist/js/types"; import { type TemplateMixin, type TemplateStaticMixin } from "./templateMixin"; -type Base = typeof NamedInMemoryEntity & Constructor & TemplateStaticMixin; +type Base = typeof InMemoryEntity & Constructor & NamedInMemoryEntityConstructor & TemplateStaticMixin; declare const Template_base: Base; -export default class Template extends Template_base { +export default class Template extends Template_base implements TemplateSchema { + constructor(data?: Partial); } export {}; diff --git a/dist/js/template.js b/dist/js/template.js index f92273c..bb1c44f 100644 --- a/dist/js/template.js +++ b/dist/js/template.js @@ -1,10 +1,19 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const entity_1 = require("@mat3ra/code/dist/js/entity"); +const NamedEntityMixin_1 = require("@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"); const templateMixin_1 = require("./templateMixin"); -class Template extends entity_1.NamedInMemoryEntity { +class Template extends entity_1.InMemoryEntity { + constructor(data = {}) { + super({ + applicationName: "", + executableName: "", + content: "", + contextProviders: [], + ...data, + }); + } } exports.default = Template; -// Apply mixins -(0, templateMixin_1.templateMixin)(Template.prototype); -(0, templateMixin_1.templateStaticMixin)(Template); +(0, NamedEntityMixin_1.namedEntityMixin)(Template.prototype); +(0, templateMixin_1.templateMixin)(Template); diff --git a/dist/js/templateMixin.d.ts b/dist/js/templateMixin.d.ts index 8766dcb..e04262a 100644 --- a/dist/js/templateMixin.d.ts +++ b/dist/js/templateMixin.d.ts @@ -1,39 +1,11 @@ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; -import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; -import type { ContextProviderNameEnum, ContextProviderSchema, TemplateSchema } from "@mat3ra/esse/dist/js/types"; -import ContextProvider from "./context/ContextProvider"; -import ContextProviderRegistryContainer from "./context/ContextProviderRegistryContainer"; -export type TemplateBase = InMemoryEntity & NamedInMemoryEntity; -export type TemplateMixin = { - isManuallyChanged: boolean; - content: string; - rendered: string | undefined; - applicationName: string | undefined; - executableName: string | undefined; - contextProviders: ContextProvider[]; - addContextProvider: (provider: ContextProvider) => void; - removeContextProvider: (provider: ContextProvider) => void; - render: (externalContext?: Record) => void; - getRenderedJSON: (context?: Record) => AnyObject; - _cleanRenderingContext: (object: Record) => Record; - getDataFromProvidersForRenderingContext: (context?: Record) => Record; - setContent: (text: string) => void; - setRendered: (text: string) => void; - getContextProvidersAsClassInstances: (providerContext?: Record) => ContextProvider[]; - getDataFromProvidersForPersistentContext: (providerContext?: Record) => Record; - getRenderingContext: (externalContext?: Record) => Record; -}; -export declare function templateMixin(item: TemplateBase): TemplateMixin & InMemoryEntity & NamedInMemoryEntity; -export type ContextProviderConfigMapEntry = { - providerCls: typeof ContextProvider; - config: ContextProviderSchema; -}; -export type ContextProviderConfigMap = Partial>; +import type { TemplateSchema } from "@mat3ra/esse/dist/js/types"; +import { type TemplateSchemaMixin } from "./generated/TemplateSchemaMixin"; +export type TemplateBase = InMemoryEntity; +export type TemplateMixin = TemplateSchemaMixin; export type TemplateStaticMixin = { - contextProviderRegistry: ContextProviderRegistryContainer | null; - setContextProvidersConfig: (classConfigMap: ContextProviderConfigMap) => void; jsonSchema: TemplateSchema; }; -export declare function templateStaticMixin(item: Constructor): TemplateStaticMixin & Constructor; +export declare function templateStaticMixin(item: Constructor): void; +export declare function templateMixin(Item: Constructor): void; diff --git a/dist/js/templateMixin.js b/dist/js/templateMixin.js index 99fdd00..c821258 100644 --- a/dist/js/templateMixin.js +++ b/dist/js/templateMixin.js @@ -3,160 +3,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.templateMixin = templateMixin; exports.templateStaticMixin = templateStaticMixin; +exports.templateMixin = templateMixin; const JSONSchemasInterface_1 = __importDefault(require("@mat3ra/esse/dist/js/esse/JSONSchemasInterface")); -const utils_1 = require("@mat3ra/utils"); -const nunjucks_1 = __importDefault(require("nunjucks")); -const ContextProviderRegistryContainer_1 = __importDefault(require("./context/ContextProviderRegistryContainer")); -function templateMixin(item) { - // @ts-ignore - const properties = { - get isManuallyChanged() { - return this.prop("isManuallyChanged", false); - }, - get content() { - return this.prop("content", ""); - }, - setContent(text) { - return this.setProp("content", text); - }, - get rendered() { - return this.prop("rendered") || this.content; - }, - setRendered(text) { - return this.setProp("rendered", text); - }, - get applicationName() { - return this.prop("applicationName"); - }, - get executableName() { - return this.prop("executableName"); - }, - get contextProviders() { - return this.prop("contextProviders", []); - }, - addContextProvider(provider) { - this.setProp("contextProviders", [...this.contextProviders, provider]); - }, - removeContextProvider(provider) { - const contextProviders = this.contextProviders.filter((p) => { - return p.name !== provider.name && p.domain !== provider.domain; - }); - this.setProp("contextProviders", contextProviders); - }, - render(externalContext) { - const renderingContext = this.getRenderingContext(externalContext); - if (!this.isManuallyChanged) { - try { - const template = nunjucks_1.default.compile(this.content); - // deepClone to pass JSON data without classes - const rendered = template.render(this._cleanRenderingContext(renderingContext)); - this.setRendered(this.isManuallyChanged ? rendered : rendered || this.content); - } - catch (e) { - console.log(`Template is not compiled: ${e}`); - console.log({ - content: this.content, - _cleanRenderingContext: this._cleanRenderingContext(renderingContext), - }); - } - } - }, - getRenderedJSON(context) { - this.render(context); - return this.toJSON(); - }, - // Remove "bulky" items and JSON stringify before passing it to rendering engine (eg. jinja) to compile. - // This way the context should still be passed in full to contextProviders, but not to final text template. - // eslint-disable-next-line class-methods-use-this - _cleanRenderingContext(object) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { job, ...clone } = object; - return utils_1.Utils.clone.deepClone(clone); - }, - /* - * @summary Initializes context provider class instances. `providerContext` is used to pass the data about any - * previously stored values. That is if data was previously saved in database, the context provider - * shall receive it on initialization through providerContext and prioritize this value over the default. - */ - getContextProvidersAsClassInstances(providerContext) { - return this.contextProviders.map((p) => { - var _a; - const providerInstance = (_a = this.constructor.contextProviderRegistry) === null || _a === void 0 ? void 0 : _a.findProviderInstanceByName(p.name); - if (!providerInstance) { - throw new Error(`Provider ${p.name} not found`); - } - const clsInstance = new providerInstance.constructor({ - ...providerInstance.config, - context: providerContext, - }); - return clsInstance; - }); - }, - /* - * @summary Extracts the the data from all context providers for further use during render. - */ - getDataFromProvidersForRenderingContext(providerContext) { - const result = {}; - this.getContextProvidersAsClassInstances(providerContext).forEach((contextProvider) => { - const context = contextProvider.yieldDataForRendering(); - Object.keys(context).forEach((key) => { - // merge context keys if they are objects otherwise override them. - result[key] = - result[key] !== null && typeof result[key] === "object" - ? // @ts-ignore - { ...result[key], ...context[key] } - : context[key]; - }); - }); - return result; - }, - /* - * @summary Extracts the the data from all context providers for further save in persistent context. - */ - // TODO: optimize logic to prevent re-initializing the context provider classes again below, reuse above function - getDataFromProvidersForPersistentContext(providerContext) { - const result = {}; - this.getContextProvidersAsClassInstances(providerContext).forEach((contextProvider) => { - // only save in the persistent context the data from providers that were edited (or able to be edited) - Object.assign(result, contextProvider.isEdited ? contextProvider.yieldData() : {}); - }); - return result; - }, - /* - * @summary Combines rendering context (in order of preference): - * - context from templates initialized with external context - * - "external" context and - */ - getRenderingContext(externalContext) { - return { - ...externalContext, - ...this.getDataFromProvidersForRenderingContext(externalContext), - }; - }, - }; - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); - return properties; -} +const TemplateSchemaMixin_1 = require("./generated/TemplateSchemaMixin"); function templateStaticMixin(item) { // @ts-ignore const properties = { - contextProviderRegistry: null, get jsonSchema() { return JSONSchemasInterface_1.default.getSchemaById("software/template"); }, - setContextProvidersConfig(classConfigMap) { - const contextProviderRegistry = new ContextProviderRegistryContainer_1.default(); - Object.entries(classConfigMap).forEach(([name, { providerCls, config }]) => { - contextProviderRegistry.addProvider({ - instance: providerCls.getConstructorConfig(config), - name, - }); - }); - this.contextProviderRegistry = contextProviderRegistry; - }, }; Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); - return properties; +} +function templateMixin(Item) { + (0, TemplateSchemaMixin_1.templateSchemaMixin)(Item.prototype); + templateStaticMixin(Item); } diff --git a/dist/js/types.d.ts b/dist/js/types.d.ts index c4367e3..4cb3bff 100644 --- a/dist/js/types.d.ts +++ b/dist/js/types.d.ts @@ -2,5 +2,5 @@ import type { ApplicationMixin, ApplicationStaticMixin } from "./applicationMixi import type { CreateApplicationConfig } from "./ApplicationRegistry"; import type { ExecutableMixin } from "./executableMixin"; import type { FlavorMixin } from "./flavorMixin"; -import type { TemplateMixin, TemplateStaticMixin } from "./templateMixin"; -export type { FlavorMixin, ExecutableMixin, ApplicationMixin, ApplicationStaticMixin, CreateApplicationConfig, TemplateMixin, TemplateStaticMixin, }; +import type { TemplateMixin } from "./templateMixin"; +export type { FlavorMixin, ExecutableMixin, ApplicationMixin, ApplicationStaticMixin, CreateApplicationConfig, TemplateMixin, }; diff --git a/package-lock.json b/package-lock.json index e7daf41..f100236 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,21 +9,17 @@ "version": "0.0.0", "license": "Apache-2.0", "dependencies": { - "@types/react-jsonschema-form": "^1.7.13", - "lodash": "^4.17.21", - "nunjucks": "^3.2.4", - "react-jsonschema-form": "^1.8.1" + "lodash": "^4.17.21" }, "devDependencies": { "@babel/eslint-parser": "^7.16.3", "@exabyte-io/eslint-config": "2025.5.13-0", - "@mat3ra/code": "2025.8.7-0", - "@mat3ra/esse": "2025.11.26-0", + "@mat3ra/code": "git+https://github.com/Exabyte-io/code.git#cf4115b459e7d308e708b606adfca7918185e525", + "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#dfa3f260d19cea3a07aac1278bcebd59d242e346", "@mat3ra/made": "2025.7.15-0", "@mat3ra/standata": "2025.10.1-0", "@mat3ra/tsconfig": "2024.6.3-0", "@mat3ra/utils": "2025.9.20-0", - "@types/nunjucks": "^3.2.6", "@typescript-eslint/eslint-plugin": "^5.9.1", "@typescript-eslint/parser": "^5.9.1", "chai": "^4.3.4", @@ -2355,18 +2351,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs2": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.28.4.tgz", - "integrity": "sha512-chjPHn3p+okNMesTjKU/pnpVT06oiJG1sVDJHTkAwYTCnVdM/2V5LI5xz3Y2y7MNngn8fQ19fpXjV3f9Jqun9w==", - "license": "MIT", - "dependencies": { - "core-js": "^2.6.12" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/runtime-corejs3": { "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.4.tgz", @@ -3194,9 +3178,9 @@ "license": "MIT" }, "node_modules/@mat3ra/code": { - "version": "2025.8.7-0", - "resolved": "https://registry.npmjs.org/@mat3ra/code/-/code-2025.8.7-0.tgz", - "integrity": "sha512-Bx5mFWQfpNU70vgSt2CR9zYWNsW7b8mU5emmPrsnGKIfKi1UH6xKwhaz7Fy77bju5NHi0iv3IE9UDXf0nr6SGQ==", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/Exabyte-io/code.git#cf4115b459e7d308e708b606adfca7918185e525", + "integrity": "sha512-LWw+caG75Z4nNHinKcKOUXzeFwZHNPXlJ9Lm6/wVJ4Y7He7mNf5YQfkYSVbctWWzYAi4IlH34ZSb6tyTS0FCCw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3234,9 +3218,9 @@ } }, "node_modules/@mat3ra/esse": { - "version": "2025.11.26-0", - "resolved": "https://registry.npmjs.org/@mat3ra/esse/-/esse-2025.11.26-0.tgz", - "integrity": "sha512-m0KZ3E8n+RvJR7cWeGstcJCXt7qxO0eCiZ97ojbBg5H2smTKLBfh4g5UF5ylJnk5PaArcPcRtLYwHcOxuPZHuA==", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/Exabyte-io/esse.git#dfa3f260d19cea3a07aac1278bcebd59d242e346", + "integrity": "sha512-fqYHPctqxOUu67owdooAaSgyFc7SLgU5zYGrT7SFysZJbUzXUd5cCY5Yl25qSIrWtJ8OmlMkHQWPmWFXJqrpZg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4898,6 +4882,7 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, "license": "MIT" }, "node_modules/@types/json-schema-merge-allof": { @@ -4918,9 +4903,9 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", "dev": true, "license": "MIT" }, @@ -4952,32 +4937,6 @@ "undici-types": "~7.16.0" } }, - "node_modules/@types/nunjucks": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@types/nunjucks/-/nunjucks-3.2.6.tgz", - "integrity": "sha512-pHiGtf83na1nCzliuAdq8GowYiXvH5l931xZ0YEHaLMNFgynpEqx+IPStlu7UaDkehfvl01e4x/9Tpwhy7Ue3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "19.2.5", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.5.tgz", - "integrity": "sha512-keKxkZMqnDicuvFoJbzrhbtdLSPhj/rZThDlKWCDbgXmUg0rEUFtRssDXKYmtXluZlIqiC5VqkCgRwzuyLHKHw==", - "license": "MIT", - "dependencies": { - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-jsonschema-form": { - "version": "1.7.13", - "resolved": "https://registry.npmjs.org/@types/react-jsonschema-form/-/react-jsonschema-form-1.7.13.tgz", - "integrity": "sha512-C2jgO7/ow76oCSfUK++jKKox17R0A7ryMYNE5hJ2dR1Ske9jhuvjIlurvzMePh+Xjk8wey0nzB2C7HFKe2pRdg==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "*", - "@types/react": "*" - } - }, "node_modules/@types/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", @@ -5261,6 +5220,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", + "dev": true, "license": "MIT" }, "node_modules/acorn": { @@ -5444,7 +5404,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -5683,6 +5643,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, "license": "MIT" }, "node_modules/assertion-error": { @@ -5821,7 +5782,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5845,7 +5806,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -6088,6 +6049,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -6339,14 +6301,6 @@ "dev": true, "license": "MIT" }, - "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true, - "license": "MIT" - }, "node_modules/core-js-compat": { "version": "3.46.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", @@ -6412,12 +6366,6 @@ "dev": true, "license": "MIT" }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, "node_modules/dag-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", @@ -7742,6 +7690,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-diff": { @@ -7772,6 +7721,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -7825,7 +7775,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -8182,7 +8132,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -8595,7 +8545,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -8696,7 +8646,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8755,7 +8705,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -8830,7 +8780,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -9273,6 +9223,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -9900,6 +9851,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -10331,7 +10283,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10354,6 +10306,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "a-sync-waterfall": "^1.0.0", @@ -10379,6 +10332,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -10666,6 +10620,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11001,7 +10956,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -11198,6 +11153,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -11209,6 +11165,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -11245,79 +11202,18 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/react-jsonschema-form": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/react-jsonschema-form/-/react-jsonschema-form-1.8.1.tgz", - "integrity": "sha512-aaDloxNAcGXOOOcdKOxxqEEn5oDlPUZgWcs8unXXB9vjBRgCF8rCm/wVSv1u2G5ih0j/BX6Ewd/WjI2g00lPdg==", - "deprecated": "react-jsonschema-form has been moved to @rjsf/core", - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime-corejs2": "^7.4.5", - "ajv": "^6.7.0", - "core-js": "^2.5.7", - "lodash": "^4.17.15", - "prop-types": "^15.5.8", - "react-is": "^16.8.4", - "react-lifecycles-compat": "^3.0.4", - "shortid": "^2.2.14" - }, - "engines": { - "node": ">=6", - "npm": ">=2.14.7" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-jsonschema-form/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/react-jsonschema-form/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "dev": true, "license": "MIT" }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -11834,33 +11730,6 @@ "node": ">=8" } }, - "node_modules/shortid": { - "version": "2.2.17", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.17.tgz", - "integrity": "sha512-GpbM3gLF1UUXZvQw6MCyulHkWbRseNO4cyBEZresZRorwl1+SLu1ZdqgVtuwqz8mB6RpwPkm541mYSqrKyJSaA==", - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8" - } - }, - "node_modules/shortid/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -12499,7 +12368,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -12956,6 +12825,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" diff --git a/package.json b/package.json index 71c42a0..71e8059 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "lint:fix": "eslint --fix --cache src/js tests/js && prettier --write src/js tests/js", "transpile": "tsc -p tsconfig.json", "prettier": "prettier --check src/js tests/js", - "prepare": "husky install" + "prepare": "husky install", + "generate-mixins": "ts-node scripts/generate-mixins.ts" }, "repository": { "type": "git", @@ -42,21 +43,17 @@ "license": "Apache-2.0", "homepage": "https://github.com/Exabyte-io/ade", "dependencies": { - "@types/react-jsonschema-form": "^1.7.13", - "lodash": "^4.17.21", - "nunjucks": "^3.2.4", - "react-jsonschema-form": "^1.8.1" + "lodash": "^4.17.21" }, "devDependencies": { "@babel/eslint-parser": "^7.16.3", "@exabyte-io/eslint-config": "2025.5.13-0", "@mat3ra/utils": "2025.9.20-0", - "@mat3ra/code": "2025.8.7-0", - "@mat3ra/esse": "2025.11.26-0", + "@mat3ra/code": "git+https://github.com/Exabyte-io/code.git#cf4115b459e7d308e708b606adfca7918185e525", + "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse#dfa3f260d19cea3a07aac1278bcebd59d242e346", "@mat3ra/made": "2025.7.15-0", "@mat3ra/standata": "2025.10.1-0", "@mat3ra/tsconfig": "2024.6.3-0", - "@types/nunjucks": "^3.2.6", "@typescript-eslint/eslint-plugin": "^5.9.1", "@typescript-eslint/parser": "^5.9.1", "chai": "^4.3.4", diff --git a/scripts/generate-mixins.ts b/scripts/generate-mixins.ts new file mode 100644 index 0000000..cb6fcad --- /dev/null +++ b/scripts/generate-mixins.ts @@ -0,0 +1,36 @@ +#!/usr/bin/env node + +/** + * Script to generate mixin properties from JSON schema + * + * This script generates mixin functions for property/holder, property/meta_holder, + * and property/proto_holder schemas automatically. + * + * Usage: + * npx ts-node scripts/generate-mixin-properties.ts + */ + +import generateSchemaMixin from "@mat3ra/code/dist/js/generateSchemaMixin"; +import allSchemas from "@mat3ra/esse/dist/js/schemas.json"; +import type { JSONSchema7 } from "json-schema"; + +/** + * Output file paths for each schema + */ +const OUTPUT_PATHS = { + "software/executable-properties": "src/js/generated/ExecutableSchemaMixin.ts", + "software/flavor-properties": "src/js/generated/FlavorSchemaMixin.ts", + "software/application-properties": "src/js/generated/ApplicationSchemaMixin.ts", + "software/template-properties": "src/js/generated/TemplateSchemaMixin.ts", +}; + +function main() { + const result = generateSchemaMixin(allSchemas as JSONSchema7[], OUTPUT_PATHS); + + if (result.errorCount > 0) { + process.exit(1); + } +} + +// Run the script if it's executed directly +main(); diff --git a/src/js/Application.ts b/src/js/Application.ts new file mode 100644 index 0000000..0aee2e0 --- /dev/null +++ b/src/js/Application.ts @@ -0,0 +1,37 @@ +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { + type DefaultableInMemoryEntityConstructor, + defaultableEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import { + type NamedInMemoryEntityConstructor, + namedEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { ApplicationSchema } from "@mat3ra/esse/dist/js/types"; + +import { + type ApplicationMixin, + type ApplicationStaticMixin, + applicationMixin, +} from "./applicationMixin"; + +type Base = typeof InMemoryEntity & + NamedInMemoryEntityConstructor & + DefaultableInMemoryEntityConstructor & + Constructor & + ApplicationStaticMixin; + +export default class Application extends (InMemoryEntity as Base) implements ApplicationSchema { + constructor(data: Partial = {}) { + super({ + ...data, + }); + } + + declare static createDefault: () => Application; +} + +namedEntityMixin(Application.prototype); +defaultableEntityMixin(Application); +applicationMixin(Application); diff --git a/src/js/ApplicationRegistry.ts b/src/js/ApplicationRegistry.ts index e1c8a74..95fbaf5 100644 --- a/src/js/ApplicationRegistry.ts +++ b/src/js/ApplicationRegistry.ts @@ -1,14 +1,18 @@ import { getOneMatchFromObject } from "@mat3ra/code/dist/js/utils/object"; -import type { ApplicationSchemaBase, ExecutableSchema } from "@mat3ra/esse/dist/js/types"; +import type { + ApplicationSchema, + ExecutableSchema, + TemplateSchema, +} from "@mat3ra/esse/dist/js/types"; import { ApplicationStandata } from "@mat3ra/standata"; -import Application from "./application"; -import Executable from "./executable"; -import Flavor from "./flavor"; -import Template from "./template"; +import Application from "./Application"; +import Executable from "./Executable"; +import Flavor from "./Flavor"; +import Template from "./Template"; type ApplicationVersion = { - [build: string]: ApplicationSchemaBase; + [build: string]: ApplicationSchema; }; type ApplicationTreeItem = { @@ -28,7 +32,7 @@ export default class ApplicationRegistry { // applications static applicationsTree?: ApplicationTree; - static applicationsArray?: ApplicationSchemaBase[]; + static applicationsArray?: ApplicationSchema[]; static createApplication({ name, version = null, build = null }: CreateApplicationConfig) { const staticConfig = ApplicationRegistry.getApplicationConfig({ name, version, build }); @@ -57,7 +61,7 @@ export default class ApplicationRegistry { } const applicationsTree: ApplicationTree = {}; - const applicationsArray: ApplicationSchemaBase[] = []; + const applicationsArray: ApplicationSchema[] = []; const allApplications = new ApplicationStandata().getAllApplicationNames(); allApplications.forEach((appName) => { @@ -85,8 +89,9 @@ export default class ApplicationRegistry { appTreeItem[version] = appVersion; - const applicationConfig: ApplicationSchemaBase = { + const applicationConfig: ApplicationSchema = { ...appData, + // @ts-ignore build: buildToUse, ...versionInfo, }; @@ -212,12 +217,15 @@ export default class ApplicationRegistry { return this.getFlavorByName(executable, config?.name); } - // flavors static getInputAsTemplates(flavor: Flavor) { - const appName = flavor.prop("applicationName", ""); - const execName = flavor.prop("executableName", ""); + return this.getInput(flavor).map((template) => new Template(template)); + } + + static getInput(flavor: Flavor): TemplateSchema[] { + const appName = flavor.applicationName || ""; + const execName = flavor.executableName || ""; - return flavor.input.map((input) => { + return flavor.input.map((input): TemplateSchema => { const inputName = input.templateName || input.name; const filtered = new ApplicationStandata().getTemplatesByName( @@ -232,15 +240,15 @@ export default class ApplicationRegistry { ); } - return new Template({ ...filtered[0], name: input.name }); + return { ...filtered[0], name: input.name || "" }; }); } - static getInputAsRenderedTemplates(flavor: Flavor, context: Record) { - return this.getInputAsTemplates(flavor).map((template) => { - return template.getRenderedJSON(context); - }); - } + // static getInputAsRenderedTemplates(flavor: Flavor, context: ContextProviderConfig) { + // return this.getInputAsTemplates(flavor).map((template) => { + // return template.setContext(context).render().toJSON(); + // }); + // } static getAllFlavorsForApplication(appName: string, version?: string) { const allExecutables = this.getExecutables({ name: appName, version }); diff --git a/src/js/Executable.ts b/src/js/Executable.ts new file mode 100644 index 0000000..cfaba03 --- /dev/null +++ b/src/js/Executable.ts @@ -0,0 +1,43 @@ +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { + type DefaultableInMemoryEntityConstructor, + defaultableEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import { + type NamedInMemoryEntityConstructor, + namedEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import { + type RuntimeItemsInMemoryEntityConstructor, + runtimeItemsMixin, +} from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { ExecutableSchema } from "@mat3ra/esse/dist/js/types"; + +import { type ExecutableMixin, executableMixin } from "./executableMixin"; + +type Base = Constructor & + RuntimeItemsInMemoryEntityConstructor & + NamedInMemoryEntityConstructor & + DefaultableInMemoryEntityConstructor & + typeof InMemoryEntity; + +export default class Executable extends (InMemoryEntity as Base) implements ExecutableSchema { + constructor(data: Partial = {}) { + super({ + monitors: [], + results: [], + postProcessors: [], + preProcessors: [], + applicationId: [], + ...data, + }); + } + + declare static createDefault: () => Executable; +} + +namedEntityMixin(Executable.prototype); +defaultableEntityMixin(Executable); +runtimeItemsMixin(Executable.prototype); +executableMixin(Executable); diff --git a/src/js/Flavor.ts b/src/js/Flavor.ts new file mode 100644 index 0000000..c774e26 --- /dev/null +++ b/src/js/Flavor.ts @@ -0,0 +1,46 @@ +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { + type DefaultableInMemoryEntityConstructor, + defaultableEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import { + namedEntityMixin, + NamedInMemoryEntityConstructor, +} from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import { + type RuntimeItemsInMemoryEntityConstructor, + runtimeItemsMixin, +} from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { FlavorSchema } from "@mat3ra/esse/dist/js/types"; + +import { type FlavorMixin, flavorMixin } from "./flavorMixin"; + +type Base = typeof InMemoryEntity & + Constructor & + RuntimeItemsInMemoryEntityConstructor & + NamedInMemoryEntityConstructor & + DefaultableInMemoryEntityConstructor; + +export default class Flavor extends (InMemoryEntity as Base) implements FlavorSchema { + constructor(data: Partial = {}) { + super({ + monitors: [], + results: [], + postProcessors: [], + preProcessors: [], + input: [], + executableId: "", + executableName: "", + applicationName: "", + ...data, + }); + } + + declare static createDefault: () => Flavor; +} + +namedEntityMixin(Flavor.prototype); +defaultableEntityMixin(Flavor); +runtimeItemsMixin(Flavor.prototype); +flavorMixin(Flavor); diff --git a/src/js/Template.ts b/src/js/Template.ts new file mode 100644 index 0000000..6ccefa7 --- /dev/null +++ b/src/js/Template.ts @@ -0,0 +1,29 @@ +import { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import { + type NamedInMemoryEntityConstructor, + namedEntityMixin, +} from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; +import type { TemplateSchema } from "@mat3ra/esse/dist/js/types"; + +import { type TemplateMixin, type TemplateStaticMixin, templateMixin } from "./templateMixin"; + +type Base = typeof InMemoryEntity & + Constructor & + NamedInMemoryEntityConstructor & + TemplateStaticMixin; + +export default class Template extends (InMemoryEntity as Base) implements TemplateSchema { + constructor(data: Partial = {}) { + super({ + applicationName: "", + executableName: "", + content: "", + contextProviders: [], + ...data, + }); + } +} + +namedEntityMixin(Template.prototype); +templateMixin(Template); diff --git a/src/js/application.ts b/src/js/application.ts deleted file mode 100644 index 7a980d0..0000000 --- a/src/js/application.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { NamedDefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; - -import { - type ApplicationMixin, - type ApplicationStaticMixin, - applicationMixin, - applicationStaticMixin, -} from "./applicationMixin"; - -type Base = typeof NamedDefaultableInMemoryEntity & - Constructor & - ApplicationStaticMixin; - -export default class Application extends (NamedDefaultableInMemoryEntity as Base) {} - -applicationMixin(Application.prototype); -applicationStaticMixin(Application); diff --git a/src/js/applicationMixin.ts b/src/js/applicationMixin.ts index f1c59bc..ff78658 100644 --- a/src/js/applicationMixin.ts +++ b/src/js/applicationMixin.ts @@ -1,66 +1,43 @@ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { DefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; -import type { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import type { Defaultable } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import type { NamedEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import type { ApplicationSchemaBase } from "@mat3ra/esse/dist/js/types"; +import type { ApplicationSchema } from "@mat3ra/esse/dist/js/types"; import { ApplicationStandata } from "@mat3ra/standata"; -import Executable from "./executable"; +import Executable from "./Executable"; +import { + type ApplicationSchemaMixin, + applicationSchemaMixin, +} from "./generated/ApplicationSchemaMixin"; -type Base = InMemoryEntity & NamedInMemoryEntity & DefaultableInMemoryEntity; +type Base = InMemoryEntity & NamedEntity & Defaultable; export type BaseConstructor = Constructor & { constructCustomExecutable?: (config: object) => Executable; }; -export type ApplicationConstructor = Constructor & ApplicationStaticMixin; - -export type ApplicationMixin = Pick< - ApplicationSchemaBase, - "summary" | "version" | "build" | "shortName" | "hasAdvancedComputeOptions" | "isLicensed" -> & { - name: Required["name"]; +export type ApplicationMixin = ApplicationSchemaMixin & { + name: Required["name"]; isUsingMaterial: boolean; }; export type DefaultApplicationConfig = Pick< - ApplicationSchemaBase, + ApplicationSchema, "name" | "shortName" | "version" | "summary" | "build" >; export type ApplicationStaticMixin = { defaultConfig: DefaultApplicationConfig; - jsonSchema: ApplicationSchemaBase; + jsonSchema: ApplicationSchema; }; -export function applicationMixin(item: Base) { +function applicationPropertiesMixin( + item: T, +): asserts item is T & ApplicationMixin { // @ts-expect-error const properties: ApplicationMixin & Base = { - get summary() { - return this.prop("summary"); - }, - - get version() { - return this.prop("version", ""); - }, - - get build() { - return this.prop("build"); - }, - - get shortName() { - return this.prop("shortName", this.name); - }, - - get hasAdvancedComputeOptions() { - return this.prop("hasAdvancedComputeOptions", false); - }, - - get isLicensed() { - return this.prop("isLicensed", false); - }, - get isUsingMaterial() { const materialUsingApplications = ["vasp", "nwchem", "espresso"]; return materialUsingApplications.includes(this.name); @@ -70,17 +47,21 @@ export function applicationMixin(item: Base) { Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); } -export function applicationStaticMixin(Application: T) { +function applicationStaticMixin(Application: T) { const properties: ApplicationStaticMixin = { get defaultConfig() { return new ApplicationStandata().getDefaultConfig(); }, get jsonSchema() { - return JSONSchemasInterface.getSchemaById( - "software/application", - ) as ApplicationSchemaBase; + return JSONSchemasInterface.getSchemaById("software/application") as ApplicationSchema; }, }; Object.defineProperties(Application, Object.getOwnPropertyDescriptors(properties)); } + +export function applicationMixin(Item: BaseConstructor) { + applicationSchemaMixin(Item.prototype); + applicationPropertiesMixin(Item.prototype); + applicationStaticMixin(Item); +} diff --git a/src/js/context/ContextProvider.ts b/src/js/context/ContextProvider.ts deleted file mode 100644 index 3bd6c87..0000000 --- a/src/js/context/ContextProvider.ts +++ /dev/null @@ -1,155 +0,0 @@ -/* - * @summary This is a standalone class that contains "data" for a property with "name". Helps facilitate UI logic. - * Can be initialized from context when user edits are present: - * - user edits the corresponding property, eg. "kpath" - * - isKpathEdited is set to `true` - * - context property is updated for the parent entity (eg. Unit) in a way that persists in Redux state - * - new entity inherits the "data" through "context" field in config - * - `extraData` field is used to store any other data that should be passed from one instance of provider - * to next one, for example data about material to track when it is changed. - * @notes Should hold static data only (see `setData` method), no classes or functions - */ -import { ContextProviderSchema, Name as ContextProviderNameEnum } from "@mat3ra/esse/dist/js/types"; -import { Utils } from "@mat3ra/utils"; -import lodash from "lodash"; - -export interface ContextProviderInstance { - constructor: typeof ContextProvider; - config: ContextProviderSchema; -} - -export interface ContextProviderStatic { - getConstructorConfig: (config: ContextProviderSchema) => ContextProviderInstance; - createConfigFromContext: (config: ContextProviderSchema) => ContextProviderSchema; - getExtraDataKeyByName: (name: string) => string; - getIsEditedKeyByName: (name: string) => string; -} - -export default class ContextProvider implements ContextProviderSchema { - config: ContextProviderSchema; - - name: ContextProviderNameEnum; - - domain?: string; - - entityName?: string; - - data?: object; - - extraData?: object; - - isEdited?: boolean; - - context?: object; - - [k: string]: unknown; - - constructor(config: ContextProviderSchema) { - this.config = config; - this.name = config.name; // property name, ie. "kpath" - this.domain = config.domain || "default"; - - // if context is passed inside config, treat it as additional config - // eslint-disable-next-line no-param-reassign - if (config.context) config = ContextProvider.createConfigFromContext(config); - - this.entityName = config.entityName || "unit"; // entity this provider yields data to, eg. "unit", "subworkflow" - this.data = config.data; // property data container - this.extraData = config.extraData; // property extraData container, used track changes to data, for example - this.isEdited = config.isEdited; // whether property was edited by user, available under `isEdited` key - - this.setIsEdited = this.setIsEdited.bind(this); - this.getData = this.getData.bind(this); - this.setData = this.setData.bind(this); - this.transformData = this.transformData.bind(this); - this.yieldData = this.yieldData.bind(this); - } - - static getConstructorConfig(config: ContextProviderSchema): ContextProviderInstance { - return { - constructor: this.prototype.constructor as typeof ContextProvider, - config, - }; - } - - static createConfigFromContext(config: ContextProviderSchema) { - const data = lodash.get(config.context, config.name); - const isEdited = lodash.get(config.context, this.getIsEditedKeyByName(config.name)); - const extraData = lodash.get(config.context, this.getExtraDataKeyByName(config.name)); - return Object.assign( - config, - data - ? { - data, - extraData, - isEdited, - } - : {}, - ); - } - - setIsEdited(isEdited: boolean) { - this.isEdited = isEdited; - } - - getData() { - return this.isEdited ? this.data : this.defaultData; - } - - setData(data: object) { - this.data = Utils.clone.deepClone(data); - } - - // override in children - // eslint-disable-next-line class-methods-use-this - get defaultData(): object { - throw new Error("Not implemented."); - } - - // override in children - // eslint-disable-next-line class-methods-use-this - transformData(data: object) { - return data; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - yieldData(...transformDataArgs: any) { - const extraDataObject = this.extraData ? { [this.extraDataKey]: this.extraData } : {}; - return { - ...extraDataObject, - // @ts-ignore - [this.name]: this.transformData(this.getData(), ...transformDataArgs), - [this.isEditedKey]: this.isEdited, - }; - } - - // override when this.data needs additional processing before making it available to rendering context - // used to calculate explicit points path, for example - yieldDataForRendering() { - return this.yieldData(); - } - - get extraDataKey() { - return `${this.name}ExtraData`; - } - - static getExtraDataKeyByName(name: string) { - return `${name}ExtraData`; - } - - get isEditedKey() { - return `is${lodash.capitalize(this.name)}Edited`; - } - - static getIsEditedKeyByName(name: string) { - return `is${lodash.capitalize(name)}Edited`; - } - - get isUnitContextProvider() { - return this.entityName === "unit"; - } - - get isSubworkflowContextProvider() { - return this.entityName === "subworkflow"; - } -} diff --git a/src/js/context/ContextProviderRegistryContainer.ts b/src/js/context/ContextProviderRegistryContainer.ts deleted file mode 100644 index 159af9e..0000000 --- a/src/js/context/ContextProviderRegistryContainer.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { ContextProviderInstance } from "./ContextProvider"; -import ContextProvider from "./ContextProvider"; - -export default class ContextProviderRegistryContainer { - _providers: { - name: string; - instance: ContextProviderInstance; - }[]; - - constructor() { - this._providers = []; - } - - get providers() { - return this._providers; - } - - set providers(p) { - this._providers = p; - } - - addProvider({ name, instance }: { name: string; instance: ContextProviderInstance }) { - this._providers.push({ - name, - instance, - }); - } - - findProviderInstanceByName(name: string) { - const provider = this.providers.find((p) => p.name === name); - return provider && provider.instance; - } - - removeProvider(providerCls: ContextProvider) { - this.providers = this.providers.filter((p) => p.name !== providerCls.name); - } - - removeProviderByName(name: string) { - this.providers = this.providers.filter((p) => p.name !== name); - } -} diff --git a/src/js/context/JSONSchemaDataProvider.ts b/src/js/context/JSONSchemaDataProvider.ts deleted file mode 100644 index 2159395..0000000 --- a/src/js/context/JSONSchemaDataProvider.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-disable class-methods-use-this */ -import JinjaContextProvider from "./JinjaContextProvider"; - -/** - * @summary Provides jsonSchema only. - */ -export default class JSONSchemaDataProvider extends JinjaContextProvider { - get jsonSchema() { - throw new Error("Not implemented."); - } -} diff --git a/src/js/context/JSONSchemaFormDataProvider.ts b/src/js/context/JSONSchemaFormDataProvider.ts deleted file mode 100644 index 05c97cc..0000000 --- a/src/js/context/JSONSchemaFormDataProvider.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* eslint-disable class-methods-use-this */ -import type { UiSchema } from "react-jsonschema-form"; - -import JSONSchemaDataProvider from "./JSONSchemaDataProvider"; - -/** - * @summary Provides jsonSchema and uiSchema for generating react-jsonschema-form - * See https://github.com/mozilla-services/react-jsonschema-form for Form UI. - * Form generation example: - * ``` - * - * ``` - */ -// TODO: MOVE to WebApp/ave or wove -export default class JSONSchemaFormDataProvider extends JSONSchemaDataProvider { - get uiSchema(): UiSchema { - throw new Error("Not implemented."); - } - - get fields() { - return {}; - } - - get defaultFieldStyles() { - return {}; - } - - get uiSchemaStyled(): UiSchema { - const schema = this.uiSchema; - return Object.fromEntries( - Object.entries(schema).map(([key, value]) => [ - key, - { - ...value, - ...this.defaultFieldStyles, - classNames: `${value.classNames || ""}`, - }, - ]), - ); - } -} diff --git a/src/js/context/JinjaContextProvider.ts b/src/js/context/JinjaContextProvider.ts deleted file mode 100644 index cdceb65..0000000 --- a/src/js/context/JinjaContextProvider.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ContextProviderSchema } from "@mat3ra/esse/dist/js/types"; - -import ContextProvider from "./ContextProvider"; - -interface JSONSchemaDataProviderConfig extends ContextProviderSchema { - isUsingJinjaVariables?: boolean; -} - -export default class JinjaContextProvider extends ContextProvider { - isUsingJinjaVariables: boolean; - - constructor(config: JSONSchemaDataProviderConfig) { - super(config); - this.isUsingJinjaVariables = Boolean(config.isUsingJinjaVariables); - } -} diff --git a/src/js/executable.ts b/src/js/executable.ts deleted file mode 100644 index 0a60939..0000000 --- a/src/js/executable.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NamedDefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import { runtimeItemsMixin } from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; -import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; - -import { type ExecutableMixin, executableMixin, executableStaticMixin } from "./executableMixin"; - -type Base = Constructor & typeof NamedDefaultableInMemoryEntity; - -export default class Executable extends (NamedDefaultableInMemoryEntity as Base) {} - -// Apply mixins -runtimeItemsMixin(Executable.prototype); -executableMixin(Executable.prototype); -executableStaticMixin(Executable); diff --git a/src/js/executableMixin.ts b/src/js/executableMixin.ts index 3b5d6c5..dbb080e 100644 --- a/src/js/executableMixin.ts +++ b/src/js/executableMixin.ts @@ -1,31 +1,30 @@ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { DefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; -import type { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; +import type { Defaultable } from "@mat3ra/code/dist/js/entity/mixins/DefaultableMixin"; +import type { NamedEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; import type { ExecutableSchema } from "@mat3ra/esse/dist/js/types"; import type { FlavorMixin } from "./flavorMixin"; +import { ExecutableSchemaMixin, executableSchemaMixin } from "./generated/ExecutableSchemaMixin"; -type BaseFlavor = FlavorMixin & NamedInMemoryEntity & InMemoryEntity; -type Base = InMemoryEntity & NamedInMemoryEntity & DefaultableInMemoryEntity; +type BaseFlavor = FlavorMixin & NamedEntity & InMemoryEntity; +type Base = InMemoryEntity & NamedEntity & Defaultable; -export function executableMixin(item: Base) { - // @ts-expect-error - const properties: ExecutableMixin & Base = { - get applicationId() { - return this.prop("applicationId", []); - }, - set applicationId(value: string[]) { - this.setProp("applicationId", value); - }, - }; +export type BaseConstructor = Constructor & { + constructCustomFlavor?: (config: object) => BaseFlavor; +}; - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); -} +export type ExecutableMixin = ExecutableSchemaMixin & { + toJSON: () => ExecutableSchema & AnyObject; +}; + +export type ExecutableStaticMixin = { + jsonSchema: ExecutableSchema; +}; -export function executableStaticMixin(Executable: Constructor) { +function executableStaticMixin(Executable: Constructor) { const properties: ExecutableStaticMixin = { get jsonSchema() { return JSONSchemasInterface.getSchemaById("software/executable") as ExecutableSchema; @@ -35,15 +34,7 @@ export function executableStaticMixin(Executable: Constructor) { Object.defineProperties(Executable, Object.getOwnPropertyDescriptors(properties)); } -export type BaseConstructor = Constructor & { - constructCustomFlavor?: (config: object) => BaseFlavor; -}; - -export type ExecutableMixin = { - applicationId: string[]; - toJSON: () => ExecutableSchema & AnyObject; -}; - -export type ExecutableStaticMixin = { - jsonSchema: ExecutableSchema; -}; +export function executableMixin(Item: BaseConstructor) { + executableSchemaMixin(Item.prototype); + executableStaticMixin(Item); +} diff --git a/src/js/flavor.ts b/src/js/flavor.ts deleted file mode 100644 index f8230b0..0000000 --- a/src/js/flavor.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NamedDefaultableInMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import { - type RuntimeItemsInMemoryEntity, - runtimeItemsMixin, -} from "@mat3ra/code/dist/js/entity/mixins/RuntimeItemsMixin"; -import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; - -import { type FlavorMixin, flavorMixin, flavorStaticMixin } from "./flavorMixin"; - -type Base = typeof NamedDefaultableInMemoryEntity & - Constructor & - Constructor; - -export default class Flavor extends (NamedDefaultableInMemoryEntity as Base) {} - -// Apply mixins -flavorMixin(Flavor.prototype); -runtimeItemsMixin(Flavor.prototype); -flavorStaticMixin(Flavor); diff --git a/src/js/flavorMixin.ts b/src/js/flavorMixin.ts index d668a6f..a061b26 100644 --- a/src/js/flavorMixin.ts +++ b/src/js/flavorMixin.ts @@ -1,68 +1,13 @@ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; import type { FlavorSchema } from "@mat3ra/esse/dist/js/types"; -type Base = InMemoryEntity & NamedInMemoryEntity; +import { type FlavorSchemaMixin, flavorSchemaMixin } from "./generated/FlavorSchemaMixin"; -type Input = Required["input"]; +export type FlavorMixin = FlavorSchemaMixin; -export type FlavorMixin = { - input: Input; - disableRenderMaterials: boolean; - executableId: string; - executableName: string; - applicationName: string; - supportedApplicationVersions?: string[]; - getInputAsRenderedTemplates: (context: Record) => Record[]; -}; - -// TODO: should we add fields from esse schema (executableId, executableName, applicationName)? -export function flavorMixin(item: Base) { - // @ts-expect-error - const properties: FlavorMixin & Base = { - get input() { - return this.prop("input", []); - }, - - get disableRenderMaterials() { - return this.prop("isMultiMaterial", false); - }, - - get executableId() { - return this.prop("executableId", ""); - }, - - get executableName() { - return this.prop("executableName", ""); - }, - - get applicationName() { - return this.prop("applicationName", ""); - }, - - get supportedApplicationVersions() { - return this.prop("supportedApplicationVersions"); - }, - - getInputAsRenderedTemplates(context: Record) { - const input = this.input; - return input.map((template) => { - if (template && typeof template === "object" && "getRenderedJSON" in template) { - return (template as any).getRenderedJSON(context); - } - return template; - }); - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); - - return properties; -} - -export function flavorStaticMixin(Flavor: Constructor) { +function flavorStaticMixin(Flavor: Constructor) { const properties: FlavorStaticMixin = { get jsonSchema() { return JSONSchemasInterface.getSchemaById("software/flavor") as FlavorSchema; @@ -75,3 +20,8 @@ export function flavorStaticMixin(Flavor: Constructor) { export type FlavorStaticMixin = { jsonSchema: FlavorSchema; }; + +export function flavorMixin(Item: Constructor) { + flavorSchemaMixin(Item.prototype); + flavorStaticMixin(Item); +} diff --git a/src/js/generated/ApplicationSchemaMixin.ts b/src/js/generated/ApplicationSchemaMixin.ts new file mode 100644 index 0000000..d136674 --- /dev/null +++ b/src/js/generated/ApplicationSchemaMixin.ts @@ -0,0 +1,56 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ApplicationPropertiesSchema } from "@mat3ra/esse/dist/js/types"; + +export type ApplicationSchemaMixin = ApplicationPropertiesSchema; + +export type ApplicationInMemoryEntity = InMemoryEntity & ApplicationSchemaMixin; + +export function applicationSchemaMixin( + item: InMemoryEntity, +): asserts item is T & ApplicationSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & ApplicationSchemaMixin = { + get shortName() { + return this.requiredProp("shortName"); + }, + set shortName(value: ApplicationPropertiesSchema["shortName"]) { + this.setProp("shortName", value); + }, + get summary() { + return this.requiredProp("summary"); + }, + set summary(value: ApplicationPropertiesSchema["summary"]) { + this.setProp("summary", value); + }, + get version() { + return this.requiredProp("version"); + }, + set version(value: ApplicationPropertiesSchema["version"]) { + this.setProp("version", value); + }, + get build() { + return this.requiredProp("build"); + }, + set build(value: ApplicationPropertiesSchema["build"]) { + this.setProp("build", value); + }, + get hasAdvancedComputeOptions() { + return this.prop( + "hasAdvancedComputeOptions", + ); + }, + set hasAdvancedComputeOptions( + value: ApplicationPropertiesSchema["hasAdvancedComputeOptions"], + ) { + this.setProp("hasAdvancedComputeOptions", value); + }, + get isLicensed() { + return this.prop("isLicensed"); + }, + set isLicensed(value: ApplicationPropertiesSchema["isLicensed"]) { + this.setProp("isLicensed", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/ExecutableSchemaMixin.ts b/src/js/generated/ExecutableSchemaMixin.ts new file mode 100644 index 0000000..80e554e --- /dev/null +++ b/src/js/generated/ExecutableSchemaMixin.ts @@ -0,0 +1,38 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { ExecutablePropertiesSchema } from "@mat3ra/esse/dist/js/types"; + +export type ExecutableSchemaMixin = ExecutablePropertiesSchema; + +export type ExecutableInMemoryEntity = InMemoryEntity & ExecutableSchemaMixin; + +export function executableSchemaMixin( + item: InMemoryEntity, +): asserts item is T & ExecutableSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & ExecutableSchemaMixin = { + get name() { + return this.requiredProp("name"); + }, + set name(value: ExecutablePropertiesSchema["name"]) { + this.setProp("name", value); + }, + get applicationId() { + return this.requiredProp("applicationId"); + }, + set applicationId(value: ExecutablePropertiesSchema["applicationId"]) { + this.setProp("applicationId", value); + }, + get hasAdvancedComputeOptions() { + return this.prop( + "hasAdvancedComputeOptions", + ); + }, + set hasAdvancedComputeOptions( + value: ExecutablePropertiesSchema["hasAdvancedComputeOptions"], + ) { + this.setProp("hasAdvancedComputeOptions", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/FlavorSchemaMixin.ts b/src/js/generated/FlavorSchemaMixin.ts new file mode 100644 index 0000000..024cb69 --- /dev/null +++ b/src/js/generated/FlavorSchemaMixin.ts @@ -0,0 +1,50 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { FlavorPropertiesSchema } from "@mat3ra/esse/dist/js/types"; + +export type FlavorSchemaMixin = FlavorPropertiesSchema; + +export type FlavorInMemoryEntity = InMemoryEntity & FlavorSchemaMixin; + +export function flavorSchemaMixin( + item: InMemoryEntity, +): asserts item is T & FlavorSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & FlavorSchemaMixin = { + get executableId() { + return this.requiredProp("executableId"); + }, + set executableId(value: FlavorPropertiesSchema["executableId"]) { + this.setProp("executableId", value); + }, + get executableName() { + return this.prop("executableName"); + }, + set executableName(value: FlavorPropertiesSchema["executableName"]) { + this.setProp("executableName", value); + }, + get applicationName() { + return this.prop("applicationName"); + }, + set applicationName(value: FlavorPropertiesSchema["applicationName"]) { + this.setProp("applicationName", value); + }, + get input() { + return this.requiredProp("input"); + }, + set input(value: FlavorPropertiesSchema["input"]) { + this.setProp("input", value); + }, + get supportedApplicationVersions() { + return this.prop( + "supportedApplicationVersions", + ); + }, + set supportedApplicationVersions( + value: FlavorPropertiesSchema["supportedApplicationVersions"], + ) { + this.setProp("supportedApplicationVersions", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/generated/TemplateSchemaMixin.ts b/src/js/generated/TemplateSchemaMixin.ts new file mode 100644 index 0000000..276af42 --- /dev/null +++ b/src/js/generated/TemplateSchemaMixin.ts @@ -0,0 +1,50 @@ +import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; +import type { TemplatePropertiesSchema } from "@mat3ra/esse/dist/js/types"; + +export type TemplateSchemaMixin = TemplatePropertiesSchema; + +export type TemplateInMemoryEntity = InMemoryEntity & TemplateSchemaMixin; + +export function templateSchemaMixin( + item: InMemoryEntity, +): asserts item is T & TemplateSchemaMixin { + // @ts-expect-error + const properties: InMemoryEntity & TemplateSchemaMixin = { + get applicationName() { + return this.requiredProp( + "applicationName", + ); + }, + set applicationName(value: TemplatePropertiesSchema["applicationName"]) { + this.setProp("applicationName", value); + }, + get applicationVersion() { + return this.prop("applicationVersion"); + }, + set applicationVersion(value: TemplatePropertiesSchema["applicationVersion"]) { + this.setProp("applicationVersion", value); + }, + get executableName() { + return this.requiredProp("executableName"); + }, + set executableName(value: TemplatePropertiesSchema["executableName"]) { + this.setProp("executableName", value); + }, + get contextProviders() { + return this.requiredProp( + "contextProviders", + ); + }, + set contextProviders(value: TemplatePropertiesSchema["contextProviders"]) { + this.setProp("contextProviders", value); + }, + get content() { + return this.requiredProp("content"); + }, + set content(value: TemplatePropertiesSchema["content"]) { + this.setProp("content", value); + }, + }; + + Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} diff --git a/src/js/index.ts b/src/js/index.ts index aa149a7..a869848 100644 --- a/src/js/index.ts +++ b/src/js/index.ts @@ -1,14 +1,12 @@ -import Application from "./application"; -import { applicationMixin, applicationStaticMixin } from "./applicationMixin"; +import Application from "./Application"; +import { applicationMixin } from "./applicationMixin"; import ApplicationRegistry from "./ApplicationRegistry"; -import ContextProvider from "./context/ContextProvider"; -import JSONSchemaFormDataProvider from "./context/JSONSchemaFormDataProvider"; -import Executable from "./executable"; +import Executable from "./Executable"; import { executableMixin } from "./executableMixin"; -import Flavor from "./flavor"; +import Flavor from "./Flavor"; import { flavorMixin } from "./flavorMixin"; -import Template from "./template"; -import { templateMixin, templateStaticMixin } from "./templateMixin"; +import Template from "./Template"; +import { templateMixin } from "./templateMixin"; const allApplications = ApplicationRegistry.getUniqueAvailableApplicationNames(); @@ -18,14 +16,10 @@ export { Flavor, Template, ApplicationRegistry, - ContextProvider, - JSONSchemaFormDataProvider, executableMixin, flavorMixin, applicationMixin, - applicationStaticMixin, templateMixin, - templateStaticMixin, allApplications, }; diff --git a/src/js/template.ts b/src/js/template.ts deleted file mode 100644 index ab2af9c..0000000 --- a/src/js/template.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; - -import { - type TemplateMixin, - type TemplateStaticMixin, - templateMixin, - templateStaticMixin, -} from "./templateMixin"; - -type Base = typeof NamedInMemoryEntity & Constructor & TemplateStaticMixin; - -export default class Template extends (NamedInMemoryEntity as Base) {} - -// Apply mixins -templateMixin(Template.prototype); -templateStaticMixin(Template); diff --git a/src/js/templateMixin.ts b/src/js/templateMixin.ts index c1e8f92..071f9d4 100644 --- a/src/js/templateMixin.ts +++ b/src/js/templateMixin.ts @@ -1,243 +1,30 @@ import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity"; -import type { NamedInMemoryEntity } from "@mat3ra/code/dist/js/entity/mixins/NamedEntityMixin"; import type { Constructor } from "@mat3ra/code/dist/js/utils/types"; import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; -import type { - ContextProviderNameEnum, - ContextProviderSchema, - TemplateSchema, -} from "@mat3ra/esse/dist/js/types"; -import { Utils } from "@mat3ra/utils"; -import nunjucks from "nunjucks"; +import type { TemplateSchema } from "@mat3ra/esse/dist/js/types"; -import ContextProvider from "./context/ContextProvider"; -import ContextProviderRegistryContainer from "./context/ContextProviderRegistryContainer"; +import { type TemplateSchemaMixin, templateSchemaMixin } from "./generated/TemplateSchemaMixin"; -export type TemplateBase = InMemoryEntity & NamedInMemoryEntity; +export type TemplateBase = InMemoryEntity; -export type TemplateMixin = { - isManuallyChanged: boolean; - content: string; - rendered: string | undefined; - applicationName: string | undefined; - executableName: string | undefined; - contextProviders: ContextProvider[]; - addContextProvider: (provider: ContextProvider) => void; - removeContextProvider: (provider: ContextProvider) => void; - render: (externalContext?: Record) => void; - getRenderedJSON: (context?: Record) => AnyObject; - _cleanRenderingContext: (object: Record) => Record; - getDataFromProvidersForRenderingContext: ( - context?: Record, - ) => Record; - setContent: (text: string) => void; - setRendered: (text: string) => void; - getContextProvidersAsClassInstances: ( - providerContext?: Record, - ) => ContextProvider[]; - getDataFromProvidersForPersistentContext: ( - providerContext?: Record, - ) => Record; - getRenderingContext: (externalContext?: Record) => Record; -}; - -export function templateMixin(item: TemplateBase) { - // @ts-ignore - const properties: TemplateMixin & TemplateBase = { - get isManuallyChanged() { - return this.prop("isManuallyChanged", false); - }, - - get content() { - return this.prop("content", ""); - }, - - setContent(text: string) { - return this.setProp("content", text); - }, - - get rendered() { - return this.prop("rendered") || this.content; - }, - - setRendered(text: string) { - return this.setProp("rendered", text); - }, - - get applicationName() { - return this.prop("applicationName"); - }, - - get executableName() { - return this.prop("executableName"); - }, - - get contextProviders() { - return this.prop("contextProviders", []); - }, - - addContextProvider(provider: ContextProvider) { - this.setProp("contextProviders", [...this.contextProviders, provider]); - }, - - removeContextProvider(provider: ContextProvider) { - const contextProviders = this.contextProviders.filter((p) => { - return p.name !== provider.name && p.domain !== provider.domain; - }); - - this.setProp("contextProviders", contextProviders); - }, - - render(externalContext?: Record) { - const renderingContext = this.getRenderingContext(externalContext); - if (!this.isManuallyChanged) { - try { - const template = nunjucks.compile(this.content); - - // deepClone to pass JSON data without classes - const rendered = template.render( - this._cleanRenderingContext(renderingContext), - ) as string; - - this.setRendered(this.isManuallyChanged ? rendered : rendered || this.content); - } catch (e) { - console.log(`Template is not compiled: ${e}`); - console.log({ - content: this.content, - _cleanRenderingContext: this._cleanRenderingContext(renderingContext), - }); - } - } - }, - - getRenderedJSON(context?: Record) { - this.render(context); - return this.toJSON(); - }, - - // Remove "bulky" items and JSON stringify before passing it to rendering engine (eg. jinja) to compile. - // This way the context should still be passed in full to contextProviders, but not to final text template. - // eslint-disable-next-line class-methods-use-this - _cleanRenderingContext(object: Record) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { job, ...clone } = object; - return Utils.clone.deepClone(clone); - }, - - /* - * @summary Initializes context provider class instances. `providerContext` is used to pass the data about any - * previously stored values. That is if data was previously saved in database, the context provider - * shall receive it on initialization through providerContext and prioritize this value over the default. - */ - getContextProvidersAsClassInstances(providerContext?: Record) { - return this.contextProviders.map((p) => { - const providerInstance = ( - this.constructor as unknown as TemplateStaticMixin - ).contextProviderRegistry?.findProviderInstanceByName(p.name); - - if (!providerInstance) { - throw new Error(`Provider ${p.name} not found`); - } - - const clsInstance = new providerInstance.constructor({ - ...providerInstance.config, - context: providerContext, - }); - - return clsInstance; - }); - }, - - /* - * @summary Extracts the the data from all context providers for further use during render. - */ - getDataFromProvidersForRenderingContext(providerContext?: Record) { - const result: AnyObject = {}; - this.getContextProvidersAsClassInstances(providerContext).forEach((contextProvider) => { - const context = contextProvider.yieldDataForRendering(); - Object.keys(context).forEach((key) => { - // merge context keys if they are objects otherwise override them. - result[key] = - result[key] !== null && typeof result[key] === "object" - ? // @ts-ignore - { ...result[key], ...context[key] } - : context[key]; - }); - }); - return result; - }, - - /* - * @summary Extracts the the data from all context providers for further save in persistent context. - */ - // TODO: optimize logic to prevent re-initializing the context provider classes again below, reuse above function - getDataFromProvidersForPersistentContext(providerContext?: Record) { - const result = {}; - this.getContextProvidersAsClassInstances(providerContext).forEach((contextProvider) => { - // only save in the persistent context the data from providers that were edited (or able to be edited) - Object.assign(result, contextProvider.isEdited ? contextProvider.yieldData() : {}); - }); - return result; - }, - - /* - * @summary Combines rendering context (in order of preference): - * - context from templates initialized with external context - * - "external" context and - */ - getRenderingContext(externalContext?: Record) { - return { - ...externalContext, - ...this.getDataFromProvidersForRenderingContext(externalContext), - }; - }, - }; - - Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); - - return properties; -} - -export type ContextProviderConfigMapEntry = { - providerCls: typeof ContextProvider; - config: ContextProviderSchema; -}; - -export type ContextProviderConfigMap = Partial< - Record ->; +export type TemplateMixin = TemplateSchemaMixin; export type TemplateStaticMixin = { - contextProviderRegistry: ContextProviderRegistryContainer | null; - setContextProvidersConfig: (classConfigMap: ContextProviderConfigMap) => void; jsonSchema: TemplateSchema; }; -export function templateStaticMixin(item: Constructor) { +export function templateStaticMixin(item: Constructor) { // @ts-ignore - const properties: TemplateStaticMixin & Constructor = { - contextProviderRegistry: null, - + const properties: TemplateStaticMixin & Constructor = { get jsonSchema() { return JSONSchemasInterface.getSchemaById("software/template") as TemplateSchema; }, - - setContextProvidersConfig(classConfigMap: ContextProviderConfigMap) { - const contextProviderRegistry = new ContextProviderRegistryContainer(); - - Object.entries(classConfigMap).forEach(([name, { providerCls, config }]) => { - contextProviderRegistry.addProvider({ - instance: providerCls.getConstructorConfig(config), - name, - }); - }); - - this.contextProviderRegistry = contextProviderRegistry; - }, }; Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties)); +} - return properties; +export function templateMixin(Item: Constructor) { + templateSchemaMixin(Item.prototype); + templateStaticMixin(Item); } diff --git a/src/js/types.ts b/src/js/types.ts index 22cac20..028a783 100644 --- a/src/js/types.ts +++ b/src/js/types.ts @@ -2,7 +2,7 @@ import type { ApplicationMixin, ApplicationStaticMixin } from "./applicationMixi import type { CreateApplicationConfig } from "./ApplicationRegistry"; import type { ExecutableMixin } from "./executableMixin"; import type { FlavorMixin } from "./flavorMixin"; -import type { TemplateMixin, TemplateStaticMixin } from "./templateMixin"; +import type { TemplateMixin } from "./templateMixin"; export type { FlavorMixin, @@ -11,5 +11,4 @@ export type { ApplicationStaticMixin, CreateApplicationConfig, TemplateMixin, - TemplateStaticMixin, }; diff --git a/src/py/mat3ra/ade/application.py b/src/py/mat3ra/ade/application.py index ed2c8c2..642a8b9 100644 --- a/src/py/mat3ra/ade/application.py +++ b/src/py/mat3ra/ade/application.py @@ -1,8 +1,8 @@ from mat3ra.code.entity import InMemoryEntitySnakeCase -from mat3ra.esse.models.software.application import ApplicationSchemaBase +from mat3ra.esse.models.software.application import ApplicationSchema -class Application(ApplicationSchemaBase, InMemoryEntitySnakeCase): +class Application(ApplicationSchema, InMemoryEntitySnakeCase): """ Application class representing a software application. diff --git a/tests/js/ApplicationRegistry.test.ts b/tests/js/ApplicationRegistry.test.ts index 9d0d4a2..7d6023a 100644 --- a/tests/js/ApplicationRegistry.test.ts +++ b/tests/js/ApplicationRegistry.test.ts @@ -1,40 +1,18 @@ /* eslint-disable no-unused-expressions */ -import { Name as ContextProviderNameEnum } from "@mat3ra/esse/dist/js/types"; import { expect } from "chai"; -import type { ContextProviderConfigMapEntry } from "src/js/templateMixin"; -import Application from "../../src/js/application"; +import Application from "../../src/js/Application"; import type { CreateApplicationConfig } from "../../src/js/ApplicationRegistry"; import ApplicationRegistry from "../../src/js/ApplicationRegistry"; -import ContextProvider from "../../src/js/context/ContextProvider"; -import Executable from "../../src/js/executable"; -import Flavor from "../../src/js/flavor"; -import Template from "../../src/js/template"; - -class MockContextProvider extends ContextProvider { - // eslint-disable-next-line class-methods-use-this - get defaultData() { - return { test: "value" }; - } -} +import Executable from "../../src/js/Executable"; +import Flavor from "../../src/js/Flavor"; +import Template from "../../src/js/Template"; describe("ApplicationRegistry", () => { beforeEach(() => { // Reset static properties before each test ApplicationRegistry.applicationsTree = undefined; ApplicationRegistry.applicationsArray = undefined; - - const mockConfig: ContextProviderConfigMapEntry = { - providerCls: MockContextProvider, - config: { name: ContextProviderNameEnum.QGridFormDataManager }, - }; - - Template.setContextProvidersConfig({ - QGridFormDataManager: mockConfig, - PlanewaveCutoffDataManager: mockConfig, - KGridFormDataManager: mockConfig, - QEPWXInputDataManager: mockConfig, - }); }); describe("createApplication", () => { @@ -350,7 +328,12 @@ describe("ApplicationRegistry", () => { }); it("should handle flavor with no input", () => { - const templates = ApplicationRegistry.getInputAsTemplates(new Flavor()); + const templates = ApplicationRegistry.getInputAsTemplates( + new Flavor({ + executableId: "espresso_pw", + input: [], + }), + ); expect(templates).to.be.an("array"); expect(templates.length).to.equal(0); @@ -359,6 +342,7 @@ describe("ApplicationRegistry", () => { it("should handle input with templateName", () => { const templates = ApplicationRegistry.getInputAsTemplates( new Flavor({ + executableId: "espresso_pw", applicationName: "espresso", executableName: "pw", input: [{ name: "input", templateName: "test_template" }], @@ -371,39 +355,6 @@ describe("ApplicationRegistry", () => { }); }); - describe("getInputAsRenderedTemplates", () => { - it("should return rendered templates for flavor input", () => { - const executable = ApplicationRegistry.getExecutableByName("espresso", "pw.x"); - const flavor = ApplicationRegistry.getFlavorByName(executable, "pw_scf"); - - if (flavor) { - const context = { test: "value" }; - const renderedTemplates = ApplicationRegistry.getInputAsRenderedTemplates( - flavor, - context, - ); - - expect(renderedTemplates).to.be.an("array"); - renderedTemplates.forEach((template) => { - expect(template).to.be.an("object"); - }); - } - }); - - it("should handle empty context", () => { - const executable = ApplicationRegistry.getExecutableByName("espresso", "pw.x"); - const flavor = ApplicationRegistry.getFlavorByName(executable, "pw_scf"); - - if (!flavor) { - throw new Error("Flavor not found"); - } - - const renderedTemplates = ApplicationRegistry.getInputAsRenderedTemplates(flavor, {}); - - expect(renderedTemplates).to.be.an("array"); - }); - }); - describe("getAllFlavorsForApplication", () => { it("should return all flavors for application without version filter", () => { const flavors = ApplicationRegistry.getAllFlavorsForApplication("espresso"); diff --git a/tests/js/ContextProviderRegistryContainer.test.ts b/tests/js/ContextProviderRegistryContainer.test.ts deleted file mode 100644 index 1405900..0000000 --- a/tests/js/ContextProviderRegistryContainer.test.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { Name as ContextProviderNameEnum } from "@mat3ra/esse/dist/js/types"; -import { expect } from "chai"; - -import ContextProvider, { - type ContextProviderInstance, -} from "../../src/js/context/ContextProvider"; -import ContextProviderRegistryContainer from "../../src/js/context/ContextProviderRegistryContainer"; - -// Mock context provider for testing -class MockContextProvider extends ContextProvider { - // eslint-disable-next-line class-methods-use-this - get defaultData() { - return { test: "value" }; - } -} - -describe("ContextProviderRegistryContainer", () => { - let container: ContextProviderRegistryContainer; - let mockProviderInstance: ContextProviderInstance; - - beforeEach(() => { - container = new ContextProviderRegistryContainer(); - mockProviderInstance = { - constructor: MockContextProvider, - config: { name: ContextProviderNameEnum.QGridFormDataManager }, - }; - }); - - describe("constructor", () => { - it("should initialize with empty providers array", () => { - expect(container.providers).to.deep.equal([]); - }); - }); - - describe("providers getter and setter", () => { - it("should get providers array", () => { - expect(container.providers).to.be.an("array"); - }); - - it("should set providers array", () => { - const newProviders = [ - { name: "provider1", instance: mockProviderInstance }, - { name: "provider2", instance: mockProviderInstance }, - ]; - container.providers = newProviders; - expect(container.providers).to.deep.equal(newProviders); - }); - }); - - describe("addProvider", () => { - it("should add a provider to the registry", () => { - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - expect(container.providers).to.have.length(1); - expect(container.providers[0]).to.deep.equal({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - }); - - it("should add multiple providers", () => { - const provider2 = { - constructor: MockContextProvider, - config: { name: ContextProviderNameEnum.PlanewaveCutoffDataManager }, - }; - - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - container.addProvider({ - name: ContextProviderNameEnum.PlanewaveCutoffDataManager, - instance: provider2, - }); - - expect(container.providers).to.have.length(2); - expect(container.providers[0].name).to.equal( - ContextProviderNameEnum.QGridFormDataManager, - ); - expect(container.providers[1].name).to.equal( - ContextProviderNameEnum.PlanewaveCutoffDataManager, - ); - }); - }); - - describe("findProviderInstanceByName", () => { - it("should find provider instance by name", () => { - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - - const found = container.findProviderInstanceByName( - ContextProviderNameEnum.QGridFormDataManager, - ); - expect(found).to.equal(mockProviderInstance); - }); - - it("should return undefined for non-existent provider", () => { - const found = container.findProviderInstanceByName( - ContextProviderNameEnum.KGridFormDataManager, - ); - expect(found).to.be.undefined; - }); - - it("should find provider when multiple providers exist", () => { - const provider2 = { - constructor: MockContextProvider, - config: { name: ContextProviderNameEnum.PlanewaveCutoffDataManager }, - }; - - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - container.addProvider({ - name: ContextProviderNameEnum.PlanewaveCutoffDataManager, - instance: provider2, - }); - - const found = container.findProviderInstanceByName( - ContextProviderNameEnum.PlanewaveCutoffDataManager, - ); - expect(found).to.equal(provider2); - }); - }); - - describe("removeProvider", () => { - it("should remove provider by ContextProvider instance", () => { - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - - const providerInstance = new MockContextProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - }); - container.removeProvider(providerInstance); - - // The removeProvider method should remove the matching provider - expect(container.providers).to.have.length(0); - }); - - it("should remove only the matching provider", () => { - const provider2 = { - constructor: MockContextProvider, - config: { name: ContextProviderNameEnum.PlanewaveCutoffDataManager }, - }; - - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - container.addProvider({ - name: ContextProviderNameEnum.PlanewaveCutoffDataManager, - instance: provider2, - }); - - const providerInstance = new MockContextProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - }); - container.removeProvider(providerInstance); - - // The removeProvider method should remove the matching provider - expect(container.providers).to.have.length(1); - expect(container.providers[0].name).to.equal( - ContextProviderNameEnum.PlanewaveCutoffDataManager, - ); - }); - - it("should not remove anything if provider not found", () => { - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - - const nonExistentProvider = new MockContextProvider({ - name: ContextProviderNameEnum.KGridFormDataManager, - }); - container.removeProvider(nonExistentProvider); - - expect(container.providers).to.have.length(1); - }); - }); - - describe("removeProviderByName", () => { - it("should remove provider by name", () => { - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - - expect(container.providers).to.have.length(1); - - container.removeProviderByName(ContextProviderNameEnum.QGridFormDataManager); - - expect(container.providers).to.have.length(0); - }); - - it("should remove only the matching provider by name", () => { - const provider2 = { - constructor: MockContextProvider, - config: { name: ContextProviderNameEnum.PlanewaveCutoffDataManager }, - }; - - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - container.addProvider({ - name: ContextProviderNameEnum.PlanewaveCutoffDataManager, - instance: provider2, - }); - - container.removeProviderByName(ContextProviderNameEnum.QGridFormDataManager); - - expect(container.providers).to.have.length(1); - expect(container.providers[0].name).to.equal( - ContextProviderNameEnum.PlanewaveCutoffDataManager, - ); - }); - - it("should not remove anything if provider name not found", () => { - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - - container.removeProviderByName(ContextProviderNameEnum.KGridFormDataManager); - - expect(container.providers).to.have.length(1); - }); - }); - - describe("integration tests", () => { - it("should handle full lifecycle: add, find, remove", () => { - // Add providers - container.addProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - instance: mockProviderInstance, - }); - container.addProvider({ - name: ContextProviderNameEnum.PlanewaveCutoffDataManager, - instance: mockProviderInstance, - }); - - // Verify they exist - expect( - container.findProviderInstanceByName(ContextProviderNameEnum.QGridFormDataManager), - ).to.equal(mockProviderInstance); - expect( - container.findProviderInstanceByName( - ContextProviderNameEnum.PlanewaveCutoffDataManager, - ), - ).to.equal(mockProviderInstance); - - // Remove one - container.removeProviderByName(ContextProviderNameEnum.QGridFormDataManager); - - // Verify state - expect( - container.findProviderInstanceByName(ContextProviderNameEnum.QGridFormDataManager), - ).to.be.undefined; - expect( - container.findProviderInstanceByName( - ContextProviderNameEnum.PlanewaveCutoffDataManager, - ), - ).to.equal(mockProviderInstance); - expect(container.providers).to.have.length(1); - }); - }); -}); diff --git a/tests/js/JSONSchemaProvider.test.ts b/tests/js/JSONSchemaProvider.test.ts deleted file mode 100644 index aa1320a..0000000 --- a/tests/js/JSONSchemaProvider.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Name as ContextProviderNameEnum } from "@mat3ra/esse/dist/js/types"; -import { expect } from "chai"; - -import JSONSchemaDataProvider from "../../src/js/context/JSONSchemaDataProvider"; -import JSONSchemaFormDataProvider from "../../src/js/context/JSONSchemaFormDataProvider"; - -describe("JSONSchemaDataProvider", () => { - it("should set isUsingJinjaVariables", () => { - const provider = new JSONSchemaDataProvider({ - name: ContextProviderNameEnum.KGridFormDataManager, - isUsingJinjaVariables: true, - }); - expect(provider.isUsingJinjaVariables).to.equal(true); - }); - - it("should throw error when accessing jsonSchema", () => { - const provider = new JSONSchemaDataProvider({ - name: ContextProviderNameEnum.KGridFormDataManager, - }); - expect(() => provider.jsonSchema).to.throw("Not implemented."); - }); -}); - -describe("JSONSchemaFormDataProvider", () => { - it("can be created", () => { - const provider = new JSONSchemaFormDataProvider({ - name: ContextProviderNameEnum.KGridFormDataManager, - }); - expect(provider).to.exist; - }); - - it("should throw error when accessing uiSchema", () => { - const provider = new JSONSchemaFormDataProvider({ - name: ContextProviderNameEnum.KGridFormDataManager, - }); - expect(() => provider.uiSchema).to.throw("Not implemented."); - }); - - it("should return empty fields object", () => { - const provider = new JSONSchemaFormDataProvider({ - name: ContextProviderNameEnum.KGridFormDataManager, - }); - expect(provider.fields).to.deep.equal({}); - }); - - it("should return empty defaultFieldStyles object", () => { - const provider = new JSONSchemaFormDataProvider({ - name: ContextProviderNameEnum.KGridFormDataManager, - }); - expect(provider.defaultFieldStyles).to.deep.equal({}); - }); - - it("should return uiSchemaStyled", () => { - class TestProvider extends JSONSchemaFormDataProvider { - // eslint-disable-next-line class-methods-use-this - get uiSchema() { - return { field1: { classNames: "test" }, field2: {} }; - } - } - const provider = new TestProvider({ - name: ContextProviderNameEnum.KGridFormDataManager, - }); - const styled = provider.uiSchemaStyled; - expect(styled).to.have.property("field1"); - expect(styled.field1).to.have.property("classNames", "test"); - }); -}); diff --git a/tests/js/application.test.ts b/tests/js/application.test.ts index e473fe9..9893063 100644 --- a/tests/js/application.test.ts +++ b/tests/js/application.test.ts @@ -1,90 +1,10 @@ /* eslint-disable no-unused-expressions */ import { expect } from "chai"; -import Application from "../../src/js/application"; -import type { CreateApplicationConfig } from "../../src/js/ApplicationRegistry"; +import Application from "../../src/js/Application"; describe("Application", () => { - const obj: CreateApplicationConfig = { name: "espresso" }; - - it("can be created", () => { - const app = new Application(obj); - expect(app.name).to.equal("espresso"); - }); - describe("applicationMixin properties", () => { - let app: Application; - - beforeEach(() => { - app = new Application(obj); - }); - - describe("summary property", () => { - it("should return summary when set", () => { - app.setProp("summary", "Test summary"); - expect(app.summary).to.equal("Test summary"); - }); - - it("should return undefined when summary is not set", () => { - expect(app.summary).to.be.undefined; - }); - }); - - describe("version property", () => { - it("should return version when set", () => { - app.setProp("version", "1.2.3"); - expect(app.version).to.equal("1.2.3"); - }); - - it("should return empty string as default when version is not set", () => { - expect(app.version).to.equal(""); - }); - }); - - describe("build property", () => { - it("should return build when set", () => { - app.setProp("build", "debug"); - expect(app.build).to.equal("debug"); - }); - - it("should return undefined when build is not set", () => { - expect(app.build).to.be.undefined; - }); - }); - - describe("shortName property", () => { - it("should return shortName when set", () => { - app.setProp("shortName", "qe"); - expect(app.shortName).to.equal("qe"); - }); - - it("should return name as default when shortName is not set", () => { - expect(app.shortName).to.equal("espresso"); - }); - }); - - describe("hasAdvancedComputeOptions property", () => { - it("should return true when set", () => { - app.setProp("hasAdvancedComputeOptions", true); - expect(app.hasAdvancedComputeOptions).to.be.true; - }); - - it("should return false as default when not set", () => { - expect(app.hasAdvancedComputeOptions).to.be.false; - }); - }); - - describe("isLicensed property", () => { - it("should return true when set", () => { - app.setProp("isLicensed", true); - expect(app.isLicensed).to.be.true; - }); - - it("should return false as default when not set", () => { - expect(app.isLicensed).to.be.false; - }); - }); - describe("isUsingMaterial property", () => { it("should return true for vasp application", () => { const vaspApp = new Application({ name: "vasp" }); @@ -109,15 +29,6 @@ describe("Application", () => { }); describe("applicationStaticMixin properties", () => { - it("should have defaultConfig with correct structure", () => { - const config = Application.defaultConfig; - expect(config).to.have.property("name", "espresso"); - expect(config).to.have.property("shortName", "qe"); - expect(config).to.have.property("version", "6.3"); - expect(config).to.have.property("summary", "Quantum ESPRESSO"); - expect(config).to.have.property("build", "GNU"); - }); - it("should return the complete defaultConfig object", () => { expect(Application.defaultConfig).to.deep.equal({ name: "espresso", diff --git a/tests/js/executable.test.ts b/tests/js/executable.test.ts index b029f21..757cb83 100644 --- a/tests/js/executable.test.ts +++ b/tests/js/executable.test.ts @@ -1,8 +1,7 @@ /* eslint-disable no-unused-expressions */ import { expect } from "chai"; -import ApplicationRegistry from "../../src/js/ApplicationRegistry"; -import Executable from "../../src/js/executable"; +import Executable from "../../src/js/Executable"; describe("Executable", () => { it("toJSON works as expected", () => { @@ -13,55 +12,6 @@ describe("Executable", () => { expect(json).to.have.property("schemaVersion"); }); - it("should find executable via ApplicationRegistry and validate JSON structure", () => { - // Find an executable using ApplicationRegistry - const executable = ApplicationRegistry.getExecutableByName("espresso", "pw.x"); - - // Verify we got a valid executable - expect(executable).to.be.instanceOf(Executable); - expect(executable.name).to.equal("pw.x"); - - // Get JSON representation - const json = executable.toJSON(); - - // Validate JSON structure contains expected properties - expect(json).to.be.an("object"); - expect(json).to.have.property("name"); - expect(json.name).to.equal("pw.x"); - - // Verify core executable properties - expect(json).to.have.property("isDefault"); - expect(json.isDefault).to.be.a("boolean"); - - expect(json).to.not.have.property("flavors"); - - // Verify arrays of configuration data - expect(json).to.have.property("monitors"); - expect(json.monitors).to.be.an("array"); - - expect(json).to.have.property("results"); - expect(json.results).to.be.an("array"); - - // The JSON should be comprehensive - expect(Object.keys(json).length).to.be.greaterThan(2); - }); - - describe("executableMixin properties", () => { - let executable: Executable; - beforeEach(() => { - executable = new Executable({ name: "test_exec" }); - }); - - it("should get default applicationId as empty array", () => { - expect(executable.applicationId).to.deep.equal([]); - }); - - it("should set and get applicationId", () => { - executable.applicationId = ["app1", "app2"]; - expect(executable.applicationId).to.deep.equal(["app1", "app2"]); - }); - }); - describe("executableStaticMixin", () => { it("should have jsonSchema property", () => { expect(Executable.jsonSchema).to.exist; diff --git a/tests/js/flavor.test.ts b/tests/js/flavor.test.ts index 6a459b4..20efe3f 100644 --- a/tests/js/flavor.test.ts +++ b/tests/js/flavor.test.ts @@ -2,7 +2,7 @@ import { expect } from "chai"; import ApplicationRegistry from "../../src/js/ApplicationRegistry"; -import Flavor from "../../src/js/flavor"; +import Flavor from "../../src/js/Flavor"; describe("Flavor", () => { it("results are correct", () => { @@ -12,90 +12,16 @@ describe("Flavor", () => { }, ); expect(pwscfFlavor?.results).to.deep.equal([ - { name: "atomic_forces" }, - { name: "fermi_energy" }, - { name: "pressure" }, - { name: "stress_tensor" }, - { name: "total_energy" }, - { name: "total_energy_contributions" }, - { name: "total_force" }, + "atomic_forces", + "fermi_energy", + "pressure", + "stress_tensor", + "total_energy", + "total_energy_contributions", + "total_force", ]); }); - describe("flavorMixin properties", () => { - let flavor: Flavor; - beforeEach(() => { - flavor = new Flavor({ name: "test_flavor" }); - }); - - it("should have default input as empty array", () => { - expect(flavor.input).to.deep.equal([]); - }); - - it("should return input when set", () => { - const input = [{ name: "param1" }, { name: "param2" }]; - flavor.setProp("input", input); - expect(flavor.input).to.deep.equal(input); - }); - - it("should have disableRenderMaterials as false by default", () => { - expect(flavor.disableRenderMaterials).to.be.false; - }); - - it("should return disableRenderMaterials as true when isMultiMaterial is set", () => { - flavor.setProp("isMultiMaterial", true); - expect(flavor.disableRenderMaterials).to.be.true; - }); - - it("should have executableId as empty string by default", () => { - expect(flavor.executableId).to.equal(""); - }); - - it("should return executableId when set", () => { - flavor.setProp("executableId", "exec123"); - expect(flavor.executableId).to.equal("exec123"); - }); - - it("should have executableName as empty string by default", () => { - expect(flavor.executableName).to.equal(""); - }); - - it("should return executableName when set", () => { - flavor.setProp("executableName", "pw"); - expect(flavor.executableName).to.equal("pw"); - }); - - it("should have applicationName as empty string by default", () => { - expect(flavor.applicationName).to.equal(""); - }); - - it("should return applicationName when set", () => { - flavor.setProp("applicationName", "espresso"); - expect(flavor.applicationName).to.equal("espresso"); - }); - - it("should have supportedApplicationVersions as undefined by default", () => { - expect(flavor.supportedApplicationVersions).to.be.undefined; - }); - - it("should return supportedApplicationVersions when set", () => { - flavor.setProp("supportedApplicationVersions", ["6.3", "7.0"]); - expect(flavor.supportedApplicationVersions).to.deep.equal(["6.3", "7.0"]); - }); - - // Added with LLM to help with coverage - it("should handle getInputAsRenderedTemplates with different template types", () => { - const mockTemplate = { getRenderedJSON: () => ({ rendered: true }) }; - const simpleTemplate = { name: "simple" }; - flavor.setProp("input", [mockTemplate, simpleTemplate]); - - const result = flavor.getInputAsRenderedTemplates({}); - expect(result).to.have.length(2); - expect(result[0]).to.deep.equal({ rendered: true }); - expect(result[1]).to.deep.equal({ name: "simple" }); - }); - }); - describe("flavorStaticMixin", () => { it("should have jsonSchema property", () => { expect(Flavor.jsonSchema).to.exist; diff --git a/tests/js/provider.tests.ts b/tests/js/provider.tests.ts deleted file mode 100644 index 0f1e1f5..0000000 --- a/tests/js/provider.tests.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Name as ContextProviderNameEnum } from "@mat3ra/esse/dist/js/types"; -import { expect } from "chai"; - -import ContextProvider from "../../src/js/context/ContextProvider"; - -describe("ContextProvider", () => { - const minimal = { name: ContextProviderNameEnum.KGridFormDataManager }; - const data = { a: "test" }; - - it("can be created", () => { - const provider = new ContextProvider(minimal); - // eslint-disable-next-line no-unused-expressions - expect(provider).to.exist; - }); - - it("sets and gets data", () => { - const provider = new ContextProvider(minimal); - provider.setData(data); - expect(() => provider.getData()).to.throw("Not implemented."); - provider.setIsEdited(true); - expect(JSON.stringify(provider.getData())).to.equal(JSON.stringify(data)); - expect(() => provider.defaultData).to.throw("Not implemented."); - }); - - it("should return extraDataKey", () => { - const provider = new ContextProvider(minimal); - expect(provider.extraDataKey).to.equal(`${provider.name}ExtraData`); - }); - - it("should return isEditedKey", () => { - const provider = new ContextProvider(minimal); - expect(provider.isEditedKey).to.include("Edited"); - expect(provider.isEditedKey).to.include("is"); - }); - - it("should return isUnitContextProvider", () => { - const provider = new ContextProvider({ ...minimal, entityName: "unit" }); - expect(provider.isUnitContextProvider).to.be.true; - const nonUnitProvider = new ContextProvider({ ...minimal, entityName: "subworkflow" }); - expect(nonUnitProvider.isUnitContextProvider).to.be.false; - }); - - it("should return isSubworkflowContextProvider", () => { - const provider = new ContextProvider({ ...minimal, entityName: "subworkflow" }); - expect(provider.isSubworkflowContextProvider).to.be.true; - const nonSubworkflowProvider = new ContextProvider({ ...minimal, entityName: "unit" }); - expect(nonSubworkflowProvider.isSubworkflowContextProvider).to.be.false; - }); - - // transform, yieldData, yieldDataForRendering -}); diff --git a/tests/js/template.test.ts b/tests/js/template.test.ts index 67fcae5..3cf6949 100644 --- a/tests/js/template.test.ts +++ b/tests/js/template.test.ts @@ -1,361 +1,21 @@ /* eslint-disable no-unused-expressions */ -import { Name as ContextProviderNameEnum } from "@mat3ra/esse/dist/js/types"; import { expect } from "chai"; -import ContextProvider from "../../src/js/context/ContextProvider"; -import Template from "../../src/js/template"; -import type { - ContextProviderConfigMap, - ContextProviderConfigMapEntry, -} from "../../src/js/templateMixin"; - -// Mock context provider class -class MockContextProvider extends ContextProvider { - // eslint-disable-next-line class-methods-use-this - get defaultData() { - return { test: "value" }; - } -} - -// Set up the static context provider registry before tests -const mockConfig: ContextProviderConfigMapEntry = { - providerCls: MockContextProvider, - config: { name: ContextProviderNameEnum.QGridFormDataManager }, -}; - -const providersConfig: ContextProviderConfigMap = { - QGridFormDataManager: mockConfig, - PlanewaveCutoffDataManager: mockConfig, - KGridFormDataManager: mockConfig, - IGridFormDataManager: mockConfig, - QPathFormDataManager: mockConfig, - IPathFormDataManager: mockConfig, - KPathFormDataManager: mockConfig, - ExplicitKPathFormDataManager: mockConfig, - ExplicitKPath2PIBAFormDataManager: mockConfig, - HubbardJContextManager: mockConfig, - HubbardUContextManager: mockConfig, - HubbardVContextManager: mockConfig, - HubbardContextManagerLegacy: mockConfig, - NEBFormDataManager: mockConfig, - BoundaryConditionsFormDataManager: mockConfig, - MLSettingsDataManager: mockConfig, - MLTrainTestSplitDataManager: mockConfig, - IonDynamicsContextProvider: mockConfig, - CollinearMagnetizationDataManager: mockConfig, - NonCollinearMagnetizationDataManager: mockConfig, - QEPWXInputDataManager: mockConfig, - QENEBInputDataManager: mockConfig, - VASPInputDataManager: mockConfig, - VASPNEBInputDataManager: mockConfig, - NWChemInputDataManager: mockConfig, -}; - -before(() => { - // Register the mock provider - Template.setContextProvidersConfig(providersConfig); -}); +import Template from "../../src/js/Template"; describe("Template", () => { - let template: Template; - - beforeEach(() => { - template = new Template({ name: "test_template" }); - }); - it("toJSON works as expected", () => { - const template = new Template({ name: "test_template" }); - template.setContent("test content"); - template.setRendered("test content"); + const template = new Template({ name: "test_template", content: "test content" }); const json = template.toJSON(); - // Check basic properties from NamedInMemoryEntity expect(json).to.have.property("name", "test_template"); expect(json).to.have.property("schemaVersion"); - - // Check required template properties expect(json).to.have.property("content", "test content"); - expect(json).to.have.property("rendered", "test content"); - - // Verify data types expect(json.content).to.be.a("string"); - expect(json.rendered).to.be.a("string"); expect(json.schemaVersion).to.be.a("string"); }); - it("toJSON includes all template properties when set", () => { - const template = new Template({ name: "test_template" }); - - // Set various properties - template.setContent("test content"); - template.setProp("isManuallyChanged", true); - template.setProp("applicationName", "espresso"); - template.setProp("executableName", "pw"); - template.setRendered("rendered content"); - - const json = template.toJSON(); - - // Check required properties - expect(json.name).to.equal("test_template"); - expect(json.content).to.equal("test content"); - expect(json.rendered).to.equal("rendered content"); - expect(json.schemaVersion).to.be.a("string"); - - // Check that the JSON contains the expected structure - expect(json).to.be.an("object"); - expect(Object.keys(json).length).to.be.greaterThan(3); - }); - - it("getRenderedJSON returns valid JSON after rendering", () => { - const template = new Template({ name: "test_template" }); - template.setContent("Hello {{ name }}!"); - template.setProp("isManuallyChanged", false); - - const json = template.getRenderedJSON({ name: "World" }); - - // Check that it returns a valid JSON object - expect(json).to.be.an("object"); - expect(json).to.have.property("name", "test_template"); - expect(json).to.have.property("content", "Hello {{ name }}!"); - expect(json).to.have.property("rendered", "Hello World!"); - expect(json).to.have.property("schemaVersion"); - }); - - describe("templateMixin properties", () => { - describe("isManuallyChanged property", () => { - it("should return false by default", () => { - expect(template.isManuallyChanged).to.be.false; - }); - - it("should return true when set", () => { - template.setProp("isManuallyChanged", true); - expect(template.isManuallyChanged).to.be.true; - }); - }); - - describe("content property", () => { - it("should return empty string by default", () => { - expect(template.content).to.equal(""); - }); - - it("should return content when set", () => { - template.setContent("test content"); - expect(template.content).to.equal("test content"); - }); - - it("should set content via setContent method", () => { - template.setContent("new content"); - expect(template.content).to.equal("new content"); - }); - }); - - describe("rendered property", () => { - it("should return content when rendered is not set", () => { - template.setContent("test content"); - expect(template.rendered).to.equal("test content"); - }); - - it("should return rendered content when set", () => { - template.setContent("test content"); - template.setRendered("rendered content"); - expect(template.rendered).to.equal("rendered content"); - }); - - it("should set rendered via setRendered method", () => { - template.setRendered("rendered text"); - expect(template.rendered).to.equal("rendered text"); - }); - }); - - describe("applicationName property", () => { - it("should return undefined by default", () => { - expect(template.applicationName).to.be.undefined; - }); - - it("should return applicationName when set", () => { - template.setProp("applicationName", "espresso"); - expect(template.applicationName).to.equal("espresso"); - }); - }); - - describe("executableName property", () => { - it("should return undefined by default", () => { - expect(template.executableName).to.be.undefined; - }); - - it("should return executableName when set", () => { - template.setProp("executableName", "pw"); - expect(template.executableName).to.equal("pw"); - }); - }); - - describe("contextProviders property", () => { - it("should return empty array by default", () => { - expect(template.contextProviders).to.deep.equal([]); - }); - - it("should return contextProviders when set", () => { - const providers = [{ name: "provider1" }, { name: "provider2" }]; - template.setProp("contextProviders", providers); - expect(template.contextProviders).to.deep.equal(providers); - }); - }); - - describe("addContextProvider method", () => { - it("should add a context provider", () => { - const provider = new MockContextProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - domain: "test", - }); - const initialLength = template.contextProviders.length; - template.addContextProvider(provider); - // The method sets the new length, so we check that it increased - expect(template.contextProviders.length).to.be.greaterThan(initialLength); - }); - }); - - describe("removeContextProvider method", () => { - it("should remove a context provider by name and domain", () => { - const provider1 = new MockContextProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - domain: "domain1", - }); - const provider2 = new MockContextProvider({ - name: ContextProviderNameEnum.PlanewaveCutoffDataManager, - domain: "domain2", - }); - template.setProp("contextProviders", [provider1, provider2]); - - template.removeContextProvider(provider1); - expect(template.contextProviders).to.deep.equal([provider2]); - }); - }); - - describe("_cleanRenderingContext method", () => { - it("should remove job property and deep clone the object", () => { - const context = { - job: { id: 123 }, - name: "test", - data: { value: 456 }, - }; - - const result = template._cleanRenderingContext(context); - expect(result).to.not.have.property("job"); - expect(result).to.have.property("name", "test"); - expect(result.data).to.deep.equal({ value: 456 }); - }); - }); - - describe("render method", () => { - it("should render template with nunjucks when not manually changed", () => { - template.setContent("Hello {{ name }}!"); - template.setProp("isManuallyChanged", false); - - template.render({ name: "World" }); - expect(template.rendered).to.equal("Hello World!"); - }); - - it("should not render when manually changed", () => { - template.setContent("Original content"); - template.setProp("isManuallyChanged", true); - - template.render({ name: "World" }); - expect(template.rendered).to.equal("Original content"); - }); - - it("should handle template compilation errors gracefully", () => { - template.setContent("Invalid template {{ name }"); - template.setProp("isManuallyChanged", false); - - // Capture console.log calls - const originalLog = console.log; - let logCalled = false; - console.log = () => { - logCalled = true; - }; - - template.render({ name: "World" }); - - expect(logCalled).to.be.true; - expect(template.rendered).to.equal("Invalid template {{ name }"); - - // Restore console.log - console.log = originalLog; - }); - }); - - describe("getRenderedJSON method", () => { - it("should render template and return JSON", () => { - template.setContent("Hello {{ name }}!"); - template.setProp("isManuallyChanged", false); - - const result = template.getRenderedJSON({ name: "World" }); - expect(result).to.have.property("name", "test_template"); - expect(template.rendered).to.equal("Hello World!"); - }); - }); - - describe("getRenderingContext method", () => { - it("should combine external context with provider context", () => { - const externalContext = { external: "value" }; - const providerContext = { provider: "data" }; - - // Mock getDataFromProvidersForRenderingContext - const originalMethod = template.getDataFromProvidersForRenderingContext; - template.getDataFromProvidersForRenderingContext = () => providerContext; - - const result = template.getRenderingContext(externalContext); - expect(result).to.deep.equal({ - external: "value", - provider: "data", - }); - - // Restore original method - template.getDataFromProvidersForRenderingContext = originalMethod; - }); - }); - - // Added with LLM to help with coverage - it("should handle getDataFromProvidersForPersistentContext with edited providers", () => { - const editedProvider = new MockContextProvider({ - name: ContextProviderNameEnum.QGridFormDataManager, - domain: "test", - }); - editedProvider.isEdited = true; - editedProvider.yieldData = () => ({ data: { value: 1 } }); - - const nonEditedProvider = new MockContextProvider({ - name: ContextProviderNameEnum.PlanewaveCutoffDataManager, - domain: "test", - }); - nonEditedProvider.isEdited = false; - nonEditedProvider.yieldData = () => ({ data: { value: 2 } }); - - template.getContextProvidersAsClassInstances = () => [ - editedProvider, - nonEditedProvider, - ]; - const result = template.getDataFromProvidersForPersistentContext(); - expect(result).to.deep.equal({ data: { value: 1 } }); - }); - - it("should throw error when provider not found", () => { - template.setProp("contextProviders", [ - { name: ContextProviderNameEnum.KGridFormDataManager }, - ]); - Template.contextProviderRegistry = null; - expect(() => template.getContextProvidersAsClassInstances()).to.throw( - /Provider .* not found/, - ); - }); - }); - describe("templateStaticMixin properties", () => { - it("should set context providers config", () => { - Template.setContextProvidersConfig(providersConfig); - expect(Template.contextProviderRegistry).to.not.be.null; - }); - it("should have jsonSchema property", () => { expect(Template.jsonSchema).to.exist; });