Skip to content

Commit 0d82444

Browse files
committed
Merge branch 'main' into epic/SOF-6265
2 parents 6dc6793 + 82a6649 commit 0d82444

File tree

6 files changed

+141
-175
lines changed

6 files changed

+141
-175
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"@babel/preset-react": "7.16.7",
4949
"@babel/register": "^7.16.0",
5050
"@babel/runtime-corejs3": "7.16.8",
51-
"@exabyte-io/esse.js": "2022.10.10-0",
51+
"@exabyte-io/esse.js": "2022.10.21-1",
5252
"crypto-js": "^4.1.1",
5353
"json-schema-merge-allof": "^0.8.1",
5454
"lodash": "^4.17.21",

src/JSONSchemasInterface.js

+47-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,43 @@ import { schemas } from "@exabyte-io/esse.js/schemas";
22
import mergeAllOf from "json-schema-merge-allof";
33

44
const schemasCache = new Map();
5+
6+
/**
7+
* We assume that each schema in the application has its own unique schemaId
8+
* Unfortunately, mergeAllOf keeps schemaId after merging, and this results in multiple different schemas with the same schemaId
9+
* Hence this function
10+
*/
11+
function removeSchemaIdsAfterAllOf(schema, clean = false) {
12+
if (clean) {
13+
const { schemaId, ...restSchema } = schema;
14+
15+
return restSchema;
16+
}
17+
18+
if (Array.isArray(schema)) {
19+
return schema.map((item) => removeSchemaIdsAfterAllOf(item));
20+
}
21+
22+
if (typeof schema !== "object") {
23+
return schema;
24+
}
25+
26+
if (schema.allOf) {
27+
const { allOf, ...restSchema } = schema;
28+
29+
return {
30+
allOf: allOf.map((innerSchema) => removeSchemaIdsAfterAllOf(innerSchema, true)),
31+
...restSchema,
32+
};
33+
}
34+
35+
return Object.fromEntries(
36+
Object.entries(schema).map(([key, value]) => {
37+
return [key, removeSchemaIdsAfterAllOf(value)];
38+
}),
39+
);
40+
}
41+
542
export class JSONSchemasInterface {
643
/**
744
*
@@ -16,13 +53,7 @@ export class JSONSchemasInterface {
1653
throw new Error(`Schema not found: ${schemaId}`);
1754
}
1855

19-
const schema = mergeAllOf(originalSchema, {
20-
resolvers: {
21-
defaultResolver: mergeAllOf.options.resolvers.title,
22-
},
23-
});
24-
25-
schemasCache.set(schemaId, schema);
56+
this.registerSchema(originalSchema);
2657
}
2758

2859
return schemasCache.get(schemaId);
@@ -32,8 +63,16 @@ export class JSONSchemasInterface {
3263
*
3364
* @param {Object} - external schema
3465
*/
35-
static registerSchema(schema) {
66+
static registerSchema(originalSchema) {
67+
const schema = mergeAllOf(removeSchemaIdsAfterAllOf(originalSchema), {
68+
resolvers: {
69+
defaultResolver: mergeAllOf.options.resolvers.title,
70+
},
71+
});
72+
3673
schemasCache.set(schema.schemaId, schema);
74+
75+
return schema;
3776
}
3877

3978
/**

src/entity/in_memory.js

+14-33
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import mergeAllOf from "json-schema-merge-allof";
21
import lodash from "lodash";
32

43
// import { ESSE } from "@exabyte-io/esse.js";
54
import { deepClone } from "../utils/clone";
6-
import { getMixSchemasByClassName, getSchemaByClassName } from "../utils/schemas";
5+
import { getSchemaByClassName } from "../utils/schemas";
76

87
// TODO: https://exabyte.atlassian.net/browse/SOF-5946
98
// const schemas = new ESSE().schemas;
@@ -195,42 +194,24 @@ export class InMemoryEntity {
195194
}
196195

197196
/**
198-
* Returns original ESSE schema with nested properties from customJsonSchemaProperties
199-
* @see customJsonSchemaProperties
200-
* @returns {Object} schema
201-
*/
202-
static get baseJSONSchema() {
203-
if (!this.customJsonSchemaProperties) {
204-
return getSchemaByClassName(this.name);
205-
}
206-
207-
const { properties, ...schema } = getSchemaByClassName(this.name);
208-
209-
return {
210-
...schema,
211-
properties: {
212-
...properties,
213-
...this.customJsonSchemaProperties,
214-
},
215-
};
216-
}
217-
218-
/**
219-
* Returns resolved JSON schema with custom properties and all mixes from schemas.js
197+
* Returns class JSON schema
220198
* @returns {Object} schema
221199
*/
222200
static get jsonSchema() {
223201
try {
224-
return mergeAllOf(
225-
{
226-
allOf: [this.baseJSONSchema, ...getMixSchemasByClassName(this.name)],
227-
},
228-
{
229-
resolvers: {
230-
defaultResolver: mergeAllOf.options.resolvers.title,
231-
},
202+
if (!this.customJsonSchemaProperties) {
203+
return getSchemaByClassName(this.name);
204+
}
205+
206+
const { properties, ...schema } = getSchemaByClassName(this.name);
207+
208+
return {
209+
...schema,
210+
properties: {
211+
...properties,
212+
...this.customJsonSchemaProperties,
232213
},
233-
);
214+
};
234215
} catch (e) {
235216
console.error(e.stack);
236217
throw e;

src/utils/schemas.js

+10-93
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,21 @@
11
import { JSONSchemasInterface } from "../JSONSchemasInterface";
22

3-
export const baseSchemas = {
4-
Material: "material",
5-
Entity: "system/entity",
6-
BankMaterial: "material",
7-
Workflow: "workflow",
8-
Subworkflow: "workflow/subworkflow",
9-
BankWorkflow: "workflow",
10-
Job: "job",
11-
Application: "software/application",
12-
Executable: "software/executable",
13-
Flavor: "software/flavor",
14-
Template: "software/template",
15-
AssertionUnit: "workflow/unit/assertion",
16-
AssignmentUnit: "workflow/unit/assignment",
17-
ConditionUnit: "workflow/unit/condition",
18-
ExecutionUnit: "workflow/unit/execution",
19-
IOUnit: "workflow/unit/io",
20-
MapUnit: "workflow/unit/map",
21-
ProcessingUnit: "workflow/unit/processing",
22-
ReduceUnit: "workflow/unit/reduce",
23-
SubworkflowUnit: "workflow/unit",
24-
Unit: "workflow/unit",
25-
Project: "project",
26-
};
27-
28-
export const entityMix = [
29-
"system/description-object",
30-
"system/base-entity-set",
31-
"system/sharing",
32-
"system/metadata",
33-
"system/defaultable",
34-
];
35-
36-
export const subWorkflowMix = ["system/system-name", "system/is-multi-material"];
37-
38-
export const workflowMix = ["workflow/base-flow", "system/history", "system/is-outdated"];
39-
40-
export const bankMaterialMix = ["material/conventional", "system/creator-account"];
41-
42-
export const bankWorkflowMix = ["system/creator-account"];
43-
44-
export const jobMix = ["system/status", "system/job-extended"];
45-
46-
export const unitMix = [
47-
"system/unit-extended",
48-
"system/status",
49-
"workflow/unit/runtime/runtime-items",
50-
];
51-
52-
export const assignmentUnitMix = ["system/scope"];
53-
54-
export const flavorMix = ["system/is-multi-material"];
55-
56-
export const systemEntityMix = ["system/entity"];
57-
58-
export const projectMix = ["system/status"];
59-
60-
export const mixSchemas = {
61-
Entity: [...entityMix],
62-
Material: [...entityMix],
63-
BankMaterial: [...entityMix, ...bankMaterialMix],
64-
Workflow: [...entityMix, ...subWorkflowMix, ...workflowMix],
65-
Subworkflow: [...subWorkflowMix],
66-
BankWorkflow: [...entityMix, ...subWorkflowMix, ...workflowMix, ...bankWorkflowMix],
67-
Job: [...entityMix, ...jobMix],
68-
Application: [...entityMix, ...systemEntityMix],
69-
Executable: [...entityMix, ...systemEntityMix],
70-
Flavor: [...entityMix, ...flavorMix, ...systemEntityMix],
71-
Template: [...entityMix, ...systemEntityMix],
72-
AssertionUnit: [...unitMix],
73-
AssignmentUnit: [...unitMix, ...assignmentUnitMix],
74-
ConditionUnit: [...unitMix],
75-
ExecutionUnit: [...unitMix],
76-
IOUnit: [...unitMix],
77-
MapUnit: [...unitMix],
78-
ProcessingUnit: [...unitMix],
79-
ReduceUnit: [...unitMix],
80-
SubworkflowUnit: [...unitMix],
81-
Unit: [...unitMix],
82-
Project: [...entityMix, ...systemEntityMix, ...projectMix],
83-
};
3+
export const schemas = {};
844

5+
/**
6+
* Returns previously registered schema for InMemoryEntity
7+
* @param {*} className
8+
* @returns
9+
*/
8510
export function getSchemaByClassName(className) {
86-
return baseSchemas[className] ? JSONSchemasInterface.schemaById(baseSchemas[className]) : null;
87-
}
88-
89-
export function getMixSchemasByClassName(className) {
90-
return mixSchemas[className]
91-
? mixSchemas[className].map((schemaId) => JSONSchemasInterface.schemaById(schemaId))
92-
: [];
11+
return schemas[className] ? JSONSchemasInterface.schemaById(schemas[className]) : null;
9312
}
9413

9514
/**
9615
* Register additional Entity classes to be resolved with jsonSchema property
9716
* @param {String} className - class name derived from InMemoryEntity
98-
* @param {String} classBaseSchema - base schemaId
99-
* @param {Array} classMixSchemas - array of schemaId to mix
17+
* @param {String} schemaId - class schemaId
10018
*/
101-
export function registerClassName(className, classBaseSchema, classMixSchemas) {
102-
baseSchemas[className] = classBaseSchema;
103-
mixSchemas[className] = classMixSchemas;
19+
export function registerClassName(className, schemaId) {
20+
schemas[className] = schemaId;
10421
}

tests/JSONSchemasInterface.tests.js

+66-22
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,91 @@
1-
import { expect } from "chai";
1+
import { assert, expect } from "chai";
22

33
import { JSONSchemasInterface } from "../src/JSONSchemasInterface";
4-
import { baseSchemas, mixSchemas } from "../src/utils/schemas";
54

65
describe("JSONSchemasInterface", () => {
7-
it("can find main schema", () => {
8-
Object.values(baseSchemas).forEach((schemaId) => {
9-
const schema = JSONSchemasInterface.schemaById(schemaId);
10-
expect(schema).to.be.an("object");
11-
});
12-
});
13-
14-
it("can find mix schemas", () => {
15-
Object.values(mixSchemas).forEach((schemaIds) => {
16-
schemaIds.forEach((schemaId) => {
17-
const schema = JSONSchemasInterface.schemaById(schemaId);
18-
expect(schema).to.be.an("object");
19-
});
20-
});
6+
it("can find schema", () => {
7+
const schema = JSONSchemasInterface.schemaById("workflow");
8+
expect(schema).to.be.an("object");
219
});
2210

2311
it("can match schemas", () => {
24-
const schemaId = Object.values(baseSchemas)[0];
2512
const schema = JSONSchemasInterface.matchSchema({
2613
schemaId: {
27-
$regex: schemaId,
14+
$regex: "workflow",
2815
},
2916
});
3017

3118
expect(schema).to.be.an("object");
3219
});
3320

34-
it("can find registered schemas", () => {
21+
it("can find registered schemas; the schema is merged and clean", () => {
3522
JSONSchemasInterface.registerSchema({
36-
schemaId: "test-schema-id",
23+
schemaId: "system/in-set",
24+
$schema: "http://json-schema.org/draft-04/schema#",
25+
title: "System in-set schema",
3726
properties: {
38-
testProp: {
27+
inSet: {
28+
type: "array",
29+
items: {
30+
allOf: [
31+
{
32+
schemaId: "system/entity-reference",
33+
$schema: "http://json-schema.org/draft-04/schema#",
34+
title: "entity reference schema",
35+
properties: {
36+
_id: {
37+
description: "entity identity",
38+
type: "string",
39+
},
40+
cls: {
41+
description: "entity class",
42+
type: "string",
43+
},
44+
slug: {
45+
description: "entity slug",
46+
type: "string",
47+
},
48+
},
49+
},
50+
{
51+
type: "object",
52+
properties: {
53+
type: {
54+
type: "string",
55+
},
56+
index: {
57+
type: "number",
58+
},
59+
},
60+
},
61+
],
62+
},
63+
},
64+
valueMapFunction: {
65+
description: "Specifies the function to convert the currentValue in UI.",
3966
type: "string",
67+
enum: [
68+
"toString",
69+
"toContactUs",
70+
"toPlusMinusSign",
71+
"toUnlimited",
72+
"toSupportSeverity",
73+
],
74+
default: "toString",
4075
},
4176
},
4277
});
4378

44-
const schema = JSONSchemasInterface.schemaById("test-schema-id");
79+
const schema = JSONSchemasInterface.schemaById("system/in-set");
80+
4581
expect(schema).to.be.an("object");
82+
assert(schema.schemaId, "system/in-set");
83+
expect(schema.properties.inSet.items.schemaId).to.be.an("undefined");
84+
expect(schema.properties.inSet.items.properties).to.be.an("object");
85+
expect(schema.properties.valueMapFunction.enum[0]).to.be.an("string");
86+
expect(schema.properties.valueMapFunction.enum[1]).to.be.an("string");
87+
expect(schema.properties.valueMapFunction.enum[2]).to.be.an("string");
88+
expect(schema.properties.valueMapFunction.enum[3]).to.be.an("string");
89+
expect(schema.properties.valueMapFunction.enum[4]).to.be.an("string");
4690
});
4791
});

0 commit comments

Comments
 (0)