diff --git a/src/JSONSchemasInterface.ts b/src/JSONSchemasInterface.ts index 4b5ddb22..4482066e 100644 --- a/src/JSONSchemasInterface.ts +++ b/src/JSONSchemasInterface.ts @@ -78,7 +78,7 @@ export class JSONSchemasInterface { /** * - * @param {Object} - external schema + * @param globalSchema */ static registerGlobalSchema(globalSchema: JSONSchema) { if (JSONSchemasInterface._schema === globalSchema) { @@ -159,4 +159,14 @@ export class JSONSchemasInterface { } return ajv.compile(schema); } + + /** + * Register global schema only if none has been registered yet. + * @param globalSchema + */ + static registerGlobalSchemaIfEmpty(globalSchema: JSONSchema) { + if (!JSONSchemasInterface._schema) { + JSONSchemasInterface.registerGlobalSchema(globalSchema); + } + } } diff --git a/src/utils/yaml.ts b/src/utils/yaml.ts index d5d0db4e..cdcf2449 100644 --- a/src/utils/yaml.ts +++ b/src/utils/yaml.ts @@ -170,7 +170,7 @@ export const esseType = new yaml.Type("!esse", { }, construct(data) { try { - JSONSchemasInterface.registerGlobalSchema(esseSchema); + JSONSchemasInterface.registerGlobalSchemaIfEmpty(esseSchema); const { filePath: schemaId, objPath } = splitReference(data); const schema = JSONSchemasInterface.schemaById(schemaId); if (objPath) { diff --git a/tests/enums.ts b/tests/enums.ts index cb343f90..34123d97 100644 --- a/tests/enums.ts +++ b/tests/enums.ts @@ -1,4 +1,4 @@ -import path from "path"; +import * as path from "path"; export const FIXTURES_DIR = path.resolve(__dirname, "./fixtures"); export const YAML_COMBINE_FILE = path.resolve(FIXTURES_DIR, "yaml_combine_tag.yml"); diff --git a/tests/fixtures/mock_esse_schema.js b/tests/fixtures/mock_esse_schema.js new file mode 100644 index 00000000..4a8d64dc --- /dev/null +++ b/tests/fixtures/mock_esse_schema.js @@ -0,0 +1,97 @@ +export const MOCK_GLOBAL_SCHEMA = { + $id: "esse-global-schema", + $schema: "http://json-schema.org/draft-04/schema#", + title: "Global schema", + type: "object", + definitions: { + "core:primitive:scalar": { + $id: "core/primitive/scalar", + $schema: "http://json-schema.org/draft-04/schema#", + title: "scalar schema", + type: "object", + required: ["value"], + properties: { + value: { + type: "number", + }, + }, + }, + "definitions:units": { + $id: "definitions/units", + pressure: { + enum: ["kbar", "pa"], + }, + }, + "core:abstract::d-data": { + $id: "core/abstract/2d-data", + $schema: "http://json-schema.org/draft-04/schema#", + title: "2 dimension data schema", + type: "object", + properties: { + xDataArray: { + description: "array containing values of x Axis", + type: "array", + }, + yDataSeries: { + $ref: "#/definitions/core:primitive::d-data-series", + }, + }, + required: ["xDataArray", "yDataSeries"], + }, + "core:primitive::d-data-series": { + $id: "core/primitive/1d-data-series", + $schema: "http://json-schema.org/draft-04/schema#", + title: "1 dimension data series schema", + type: "array", + items: { + type: "array", + minItems: 1, + items: { + type: ["number", "string"], + }, + }, + }, + "methods-directory:physical:pw": { + $id: "methods-directory/physical/pw", + $schema: "http://json-schema.org/draft-04/schema#", + title: "Plane wave method unit schema", + description: "Approximating the electronic wave function with a plane wave basis", + type: "object", + properties: { + name: { + type: "string", + }, + categories: { + properties: { + tier1: { + description: "top-level category", + type: "string", + }, + tier2: { + description: "second level category", + type: "string", + }, + tier3: { + description: "third level category", + type: "string", + }, + type: { + description: "general type of the entity", + type: "string", + }, + subtype: { + description: "general subtype of the entity", + type: "string", + }, + }, + }, + tags: { + type: "array", + items: { + type: "string", + }, + }, + }, + }, + }, +}; diff --git a/tests/fixtures/schemas.js b/tests/fixtures/rjsf_schemas.js similarity index 100% rename from tests/fixtures/schemas.js rename to tests/fixtures/rjsf_schemas.js diff --git a/tests/utils/schemas.tests.ts b/tests/utils/schemas.tests.ts index 86304d22..44d5f3ef 100644 --- a/tests/utils/schemas.tests.ts +++ b/tests/utils/schemas.tests.ts @@ -13,7 +13,7 @@ import { TREE_SIMPLE, TREE_STATIC_TERMINAL, UNEVEN_TREE, -} from "../fixtures/schemas"; +} from "../fixtures/rjsf_schemas"; describe("RJSF schema", () => { it("dependencies block can be created from tree", () => { diff --git a/tests/utils/yaml.combine.tests.ts b/tests/utils/yaml.combine.tests.ts index 5a4f96b2..51f3bbc5 100644 --- a/tests/utils/yaml.combine.tests.ts +++ b/tests/utils/yaml.combine.tests.ts @@ -5,20 +5,24 @@ import fs from "fs"; import yaml from "js-yaml"; import lodash from "lodash"; +import { JSONSchemasInterface } from "../../src/JSONSchemasInterface"; import { combineType, esseType } from "../../src/utils/yaml"; import { YAML_COMBINE_FILE } from "../enums"; +import { MOCK_GLOBAL_SCHEMA } from "../fixtures/mock_esse_schema"; const combineSchema = yaml.DEFAULT_SCHEMA.extend([combineType, esseType]); describe("YAML tag: !combine", () => { let yamlFixture; + let parsed; before(() => { + JSONSchemasInterface.registerGlobalSchema(MOCK_GLOBAL_SCHEMA); yamlFixture = fs.readFileSync(YAML_COMBINE_FILE, "utf8"); + parsed = yaml.load(yamlFixture, { schema: combineSchema }); }); it("should correctly parse a custom !combine tag with forEach and config keys", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [ { name: "mytest", a: 1, b: 3, c: 5 }, { name: "mytest", a: 1, b: 4, c: 5 }, @@ -30,72 +34,57 @@ describe("YAML tag: !combine", () => { }); it("should correctly parse a custom !combine tag with only a name key", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [{ name: "mytest" }]; - expect(parsed.case2).to.have.deep.members(expectedResult); }); it("should correctly parse a custom !combine tag with forEach key and no values", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [{ name: "mytest" }]; - expect(parsed.case3).to.have.deep.members(expectedResult); }); it("should correctly parse a custom !combine tag with an empty forEach key and a config key", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [{ name: "mytest", c: 5 }]; - expect(parsed.case4).to.have.deep.members(expectedResult); }); it("should correctly generate name based on template", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [ { name: "A1 with B2 and C5", a: 1, b: "two", c: 5 }, { name: "A1 with B4 and C5", a: 1, b: "four", c: 5 }, ]; - expect(parsed.case5).to.have.deep.members(expectedResult); }); it("should correctly parse a custom !combine tag with additional property", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [ { name: "mytest", a: 1, b: 3 }, { name: "mytest", a: 1, b: 4 }, { name: "additional property", x: 7 }, ]; - expect(parsed.case6).to.have.deep.members(expectedResult); }); it("should correctly parse a custom !combine tag with additional property from !combine tag", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [ { name: "mytest", a: 1, b: 3 }, { name: "mytest", a: 1, b: 4 }, { name: "additional property", x: 7, y: 9 }, { name: "additional property", x: 8, y: 9 }, ]; - expect(parsed.case7).to.have.deep.members(expectedResult); }); it("should create an additional config when falsy parameter is provided", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [ { name: "A1 with B2", a: 1, b: "two" }, { name: "A1 with B4", a: 1, b: "four" }, { name: "A1", a: 1 }, ]; - expect(parsed.case8).to.have.deep.members(expectedResult); }); it("should create all combinations of n optional parameters", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [ { name: "optional params", a: 1 }, { name: "optional params", a: 1, b: 2 }, @@ -104,19 +93,15 @@ describe("YAML tag: !combine", () => { { name: "optional params", a: 1, b: 2, c: 4 }, { name: "optional params", a: 1, b: 3, c: 4 }, ]; - expect(parsed.case9).to.have.deep.members(expectedResult); }); it("should allow to exclude certain parameter-specified combinations", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [{ name: "ignore test", a: { c: 3 }, d: 4 }]; - expect(parsed.case10).to.have.deep.members(expectedResult); }); it("should use the push action to add value to an array parameter", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [ { name: "push test", units: [{ a: 1 }, { b: 4 }] }, { name: "push test", units: [{ a: 2 }, { b: 4 }] }, @@ -134,7 +119,6 @@ describe("YAML tag: !combine", () => { }); it("should use cloned objects when pushing to array", () => { - const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const [config1, config2] = parsed.case12; // deleting property in one should not affect the other diff --git a/tests/utils/yaml.esse.tests.ts b/tests/utils/yaml.esse.tests.ts index ec46e9fb..21ea2cc3 100644 --- a/tests/utils/yaml.esse.tests.ts +++ b/tests/utils/yaml.esse.tests.ts @@ -3,16 +3,24 @@ import { expect } from "chai"; import fs from "fs"; import yaml from "js-yaml"; +import { JSONSchemasInterface } from "../../src/JSONSchemasInterface"; import { esseType } from "../../src/utils/yaml"; import { YAML_ESSE_FILE } from "../enums"; +import { MOCK_GLOBAL_SCHEMA } from "../fixtures/mock_esse_schema"; const yamlSchema = yaml.DEFAULT_SCHEMA.extend([esseType]); describe("YAML tag: !esse", () => { - const yamlFixture = fs.readFileSync(YAML_ESSE_FILE, "utf8"); + let yamlFixture; + let parsed; + + before(() => { + JSONSchemasInterface.registerGlobalSchema(MOCK_GLOBAL_SCHEMA); + yamlFixture = fs.readFileSync(YAML_ESSE_FILE, "utf8"); + parsed = yaml.load(yamlFixture, { schema: yamlSchema }); + }); it("should correctly parse a custom !esse tag and return ESSE schema", () => { - const parsed = yaml.load(yamlFixture, { schema: yamlSchema }); const expected = { $id: "core/primitive/scalar", $schema: "http://json-schema.org/draft-04/schema#", @@ -29,24 +37,20 @@ describe("YAML tag: !esse", () => { }); it("should return the original data when an error occurs", () => { - const parsed = yaml.load(yamlFixture, { schema: yamlSchema }); expect(parsed.case2).to.be.equal("non-existent-schema-id"); }); it("should parse a custom !esse tag and return a value from the ESSE schema", () => { - const parsed = yaml.load(yamlFixture, { schema: yamlSchema }); const expected = ["kbar", "pa"]; expect(parsed.case3).to.have.deep.members(expected); }); it("should correctly return nested value from esse schema", () => { - const parsed = yaml.load(yamlFixture, { schema: yamlSchema }); const expected = "array containing values of x Axis"; expect(parsed.case4).to.be.eql(expected); }); it("should correctly return array item from esse schema", () => { - const parsed = yaml.load(yamlFixture, { schema: yamlSchema }); const expected = "yDataSeries"; expect(parsed.case5).to.be.eql(expected); });