From 5f0c8a5b30ffab97bad3f2d3d452d318540c014e Mon Sep 17 00:00:00 2001 From: Mats Johansen Date: Thu, 22 Feb 2024 13:13:30 +0100 Subject: [PATCH 1/6] feat(json validation): add validation for options --- package-lock.json | 6 + package.json | 1 + packages/demo/public/options.json | 2 - packages/lib/src/components/Options.wc.svelte | 13 ++ .../lib/src/interfaces/options.schema.json | 153 ++++++++++++++++++ 5 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 packages/lib/src/interfaces/options.schema.json diff --git a/package-lock.json b/package-lock.json index 8347968f..240184e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.3-0", "license": "MIT", "dependencies": { + "@exodus/schemasafe": "^1.3.0", "chart.js": "^4.4.0", "svelte-dnd-action": "^0.9.26", "uuid": "^9.0.0" @@ -492,6 +493,11 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", diff --git a/package.json b/package.json index 9cc75ef1..ce963b9c 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "vitest": "^0.34.2" }, "dependencies": { + "@exodus/schemasafe": "^1.3.0", "chart.js": "^4.4.0", "svelte-dnd-action": "^0.9.26", "uuid": "^9.0.0" diff --git a/packages/demo/public/options.json b/packages/demo/public/options.json index 7dc8d0fa..7c7fe913 100644 --- a/packages/demo/public/options.json +++ b/packages/demo/public/options.json @@ -145,8 +145,6 @@ { "stratifierCode": "Histlogoies", "stratumCode": "1" - }, - { } ] } diff --git a/packages/lib/src/components/Options.wc.svelte b/packages/lib/src/components/Options.wc.svelte index a3db079a..0cbb5b7c 100644 --- a/packages/lib/src/components/Options.wc.svelte +++ b/packages/lib/src/components/Options.wc.svelte @@ -16,10 +16,23 @@ import { lensOptions } from "../stores/options"; import { catalogue } from "../stores/catalogue"; import type { Criteria } from "../types/treeData"; + import optionsSchema from "../interfaces/options.schema.json"; + import { parser } from "@exodus/schemasafe"; export let options: object = {}; export let catalogueData: Criteria[] = []; + /** + * Validate the options against the schema + */ + const parse = parser(optionsSchema, { includeErrors: true }); + $: { + const validJSON = parse(JSON.stringify(options)); + if (options !== {} && options !== "" && validJSON.errors) { + console.error("Lens-Options: ", validJSON.errors); + } + } + $: $lensOptions = options; $: $catalogue = catalogueData; diff --git a/packages/lib/src/interfaces/options.schema.json b/packages/lib/src/interfaces/options.schema.json new file mode 100644 index 00000000..d07b0476 --- /dev/null +++ b/packages/lib/src/interfaces/options.schema.json @@ -0,0 +1,153 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/product.schema.json", + "title": "Product", + "description": "A product in the catalog", + "type": "object", + "properties": { + "chartOptions": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": "object", + "properties": { + "legendMapping": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": "string", + "pattern": "^.+$" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + }, + "hintText": { + "type": "array", + "items": { + "type": "string", + "pattern": "^.+$" + } + }, + "aggregations": { + "type": "array", + "items": { + "type": "string", + "pattern": "^.+$" + } + }, + "tooltips": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": "string", + "pattern": "^.+$" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + }, + "tableOptions": { + "type": "object", + "properties": { + "headerData": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "pattern": "^.+$" + }, + "dataKey": { + "type": "string", + "pattern": "^.+$" + }, + "aggregatedDataKeys": { + "type": "array", + "items": { + "type": "object", + "properties": { + "groupCode": { + "type": "string", + "pattern": "^.+$" + }, + "stratifierCode": { + "type": "string", + "pattern": "^.+$" + }, + "stratumCode": { + "type": "string", + "pattern": "^.+$" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + } + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [ + "title" + ] + } + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": ["headerData"] + }, + "resultSummaryOptions": { + "type": "object", + "properties": { + "title": { + "type": "string", + "pattern": "^.+$" + }, + "infoButtonText": { + "type": "string", + "pattern": "^.+$" + }, + "dataTypes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "pattern": "^.+$" + }, + "dataKey": { + "type": "string", + "pattern": "^.+$" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + } + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] +} \ No newline at end of file From dce505d5f72a8ca73013fcdde0e2e2dac1af1dd9 Mon Sep 17 00:00:00 2001 From: Mats Johansen Date: Mon, 26 Feb 2024 15:41:08 +0100 Subject: [PATCH 2/6] feat(json validation): add icon urls to options --- .../lib/src/interfaces/options.schema.json | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/lib/src/interfaces/options.schema.json b/packages/lib/src/interfaces/options.schema.json index d07b0476..4f492bf2 100644 --- a/packages/lib/src/interfaces/options.schema.json +++ b/packages/lib/src/interfaces/options.schema.json @@ -5,6 +5,29 @@ "description": "A product in the catalog", "type": "object", "properties": { + "iconOptions": { + "type": "object", + "properties": { + "infoUrl": { + "type": "string", + "pattern": "^.+$", + "description": "The icon to use for the info button" + }, + "addUrl": { + "type": "string", + "pattern": "^.+$", + "description": "The icon to use for the add button in the catalogue" + }, + "toggleUrl": { + "type": "string", + "pattern": "^.+$", + "description": "The icon to use for the toggle button in the catalogue" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + }, "chartOptions": { "type": "object", "patternProperties": { @@ -27,11 +50,13 @@ "type": "array", "items": { "type": "string", - "pattern": "^.+$" + "pattern": "^.+$", + "description": "The hint text to display as overlay of the info button" } }, "aggregations": { "type": "array", + "description": "add strings of other data keys to include in the chart", "items": { "type": "string", "pattern": "^.+$" @@ -42,7 +67,8 @@ "patternProperties": { "^.+$": { "type": "string", - "pattern": "^.+$" + "pattern": "^.+$", + "description": "The tooltip to display while hovering over the chart data" } }, "additionalProperties": false, @@ -69,14 +95,17 @@ "properties": { "title": { "type": "string", + "description": "the title of the column", "pattern": "^.+$" }, "dataKey": { "type": "string", + "description": "a single key to display in the table", "pattern": "^.+$" }, "aggregatedDataKeys": { "type": "array", + "description": "an array of keys to aggregate and display in the table as single value", "items": { "type": "object", "properties": { @@ -134,6 +163,30 @@ "dataKey": { "type": "string", "pattern": "^.+$" + }, + "aggregatedDataKeys": { + "type": "array", + "description": "an array of keys to aggregate and display in the result summary as single value", + "items": { + "type": "object", + "properties": { + "groupCode": { + "type": "string", + "pattern": "^.+$" + }, + "stratifierCode": { + "type": "string", + "pattern": "^.+$" + }, + "stratumCode": { + "type": "string", + "pattern": "^.+$" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + } } }, "additionalProperties": false, From e2d6942aecd58e8c3975e23522f4f70623600f12 Mon Sep 17 00:00:00 2001 From: Mats Johansen Date: Tue, 27 Feb 2024 13:55:03 +0100 Subject: [PATCH 3/6] feat(json validation): add catalogue schema --- packages/lib/src/components/Options.wc.svelte | 30 +++- .../lib/src/interfaces/catalogue.schema.json | 130 ++++++++++++++++++ .../lib/src/interfaces/options.schema.json | 5 +- 3 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 packages/lib/src/interfaces/catalogue.schema.json diff --git a/packages/lib/src/components/Options.wc.svelte b/packages/lib/src/components/Options.wc.svelte index 0cbb5b7c..e413ba12 100644 --- a/packages/lib/src/components/Options.wc.svelte +++ b/packages/lib/src/components/Options.wc.svelte @@ -17,22 +17,40 @@ import { catalogue } from "../stores/catalogue"; import type { Criteria } from "../types/treeData"; import optionsSchema from "../interfaces/options.schema.json"; + import catalogueSchema from "../interfaces/catalogue.schema.json"; import { parser } from "@exodus/schemasafe"; + import type { LensOptions } from "../types/options"; - export let options: object = {}; + export let options: LensOptions = {}; export let catalogueData: Criteria[] = []; /** - * Validate the options against the schema + * Validate the options against the schema before passing them to the store */ - const parse = parser(optionsSchema, { includeErrors: true }); + $: { + const parse = parser(optionsSchema, { + includeErrors: true, + allErrors: true, + }); const validJSON = parse(JSON.stringify(options)); - if (options !== {} && options !== "" && validJSON.errors) { + if (validJSON.valid === true) { + $lensOptions = options; + } else if (typeof options === "object") { console.error("Lens-Options: ", validJSON.errors); } } - $: $lensOptions = options; - $: $catalogue = catalogueData; + $: { + const parse = parser(catalogueSchema, { + includeErrors: true, + allErrors: true, + }); + const validJSON = parse(JSON.stringify(catalogueData)); + if (validJSON.valid === true) { + $catalogue = catalogueData; + } else if (typeof catalogueData === "object") { + console.error("Lens-Options: ", validJSON.errors); + } + } diff --git a/packages/lib/src/interfaces/catalogue.schema.json b/packages/lib/src/interfaces/catalogue.schema.json new file mode 100644 index 00000000..e6e12456 --- /dev/null +++ b/packages/lib/src/interfaces/catalogue.schema.json @@ -0,0 +1,130 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Search Parameter Catalogue", + "description": "A catalogue of search parameters", + "type": "array", + "items": { + "$ref": "#/$defs/categoryItem" + }, + "$defs": { + "childCategories": { + "type": "array", + "items": { + "$ref": "#/$defs/categoryItem" + } + }, + "categoryItem": { + "type": "object", + "properties": { + "key": { + "type": "string", + "pattern": "^.+$" + }, + "name": { + "type": "string", + "pattern": "^.+$" + }, + "subCategoryName": { + "type": "string", + "pattern": "^.+$" + }, + "infoButtonText": { + "type": "array", + "description": "The text to display in the info button", + "items": { + "type": "string", + "pattern": "^.*$" + } + }, + "system": { + "type": "string", + "pattern": "^.*$" + }, + "fieldType": { + "enum": [ + "single-select", + "number", + "autocomplete" + ] + }, + "type": { + "enum": [ + "EQUALS", + "BETWEEN" + ] + }, + "childCategories": { + "$ref": "#/$defs/childCategories" + }, + "criteria": { + "$ref": "#/$defs/criteria" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [ + "key", + "name" + ] + }, + "criteria": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string", + "pattern": "^.+$" + }, + "name": { + "type": "string", + "pattern": "^.+$" + }, + "description": { + "type": "string", + "pattern": "^.*$" + }, + "infoButtonText": { + "type": "array", + "description": "The text to display in the info button", + "items": { + "type": "string", + "pattern": "^.+$" + } + }, + "aggregatedValue": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "pattern": "^.+$" + }, + "name": { + "type": "string", + "pattern": "^.+$" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [ + "value", + "name" + ] + } + } + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [ + "key", + "name" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/lib/src/interfaces/options.schema.json b/packages/lib/src/interfaces/options.schema.json index 4f492bf2..13907a75 100644 --- a/packages/lib/src/interfaces/options.schema.json +++ b/packages/lib/src/interfaces/options.schema.json @@ -1,8 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://example.com/product.schema.json", - "title": "Product", - "description": "A product in the catalog", + "title": "Lens Options", + "description": "The options for the lens", "type": "object", "properties": { "iconOptions": { From 5b26467734f76d706e0235a617349a6b1c2bf7df Mon Sep 17 00:00:00 2001 From: Mats Johansen Date: Thu, 16 May 2024 14:42:28 +0200 Subject: [PATCH 4/6] feat(json schema): add options schemas --- packages/lib/src/components/Options.wc.svelte | 10 +++- .../lib/src/interfaces/options.schema.json | 50 ++++++++++++++++--- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/packages/lib/src/components/Options.wc.svelte b/packages/lib/src/components/Options.wc.svelte index 19031957..e4a20c94 100644 --- a/packages/lib/src/components/Options.wc.svelte +++ b/packages/lib/src/components/Options.wc.svelte @@ -38,7 +38,10 @@ if (validJSON.valid === true) { $lensOptions = options; } else if (typeof options === "object") { - console.error("Lens-Options: ", validJSON.errors); + console.error( + "Lens-Options are not conform with the JSON schema", + validJSON.errors, + ); } } @@ -51,7 +54,10 @@ if (validJSON.valid === true) { $catalogue = catalogueData; } else if (typeof catalogueData === "object") { - console.error("Lens-Options: ", validJSON.errors); + console.error( + "Catalogue is not conform with the JSON schema", + validJSON.errors, + ); } } diff --git a/packages/lib/src/interfaces/options.schema.json b/packages/lib/src/interfaces/options.schema.json index 13907a75..d455c696 100644 --- a/packages/lib/src/interfaces/options.schema.json +++ b/packages/lib/src/interfaces/options.schema.json @@ -12,15 +12,23 @@ "pattern": "^.+$", "description": "The icon to use for the info button" }, - "addUrl": { + "deleteUrl": { "type": "string", "pattern": "^.+$", - "description": "The icon to use for the add button in the catalogue" + "description": "The icon to use for the info button" }, - "toggleUrl": { - "type": "string", - "pattern": "^.+$", - "description": "The icon to use for the toggle button in the catalogue" + "selectAll": { + "type": "object", + "properties": { + "text": { + "type": "string", + "pattern": "^.+$", + "description": "The text to display for the select all button" + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] } }, "additionalProperties": false, @@ -61,6 +69,31 @@ "pattern": "^.+$" } }, + "accumulatedValues": { + "type": "array", + "description": "aggregate values of other data keys to include in the chart", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^.+$", + "description": "The name to be displayed in the chart" + }, + "values": { + "type": "array", + "items": { + "type": "string", + "pattern": "^.+$", + "description": "The data key to be aggregated" + } + } + }, + "additionalProperties": false, + "unevaluatedProperties": false, + "required": [] + } + }, "tooltips": { "type": "object", "patternProperties": { @@ -133,6 +166,11 @@ "title" ] } + }, + "claimedText": { + "type": "string", + "pattern": "^.+$", + "description": "The text to be displayed when query is being executed" } }, "additionalProperties": false, From d600cda694c551760cf5d0771b2f2ef8b5bec12d Mon Sep 17 00:00:00 2001 From: Patrick Skowronek Date: Thu, 23 May 2024 10:37:40 +0200 Subject: [PATCH 5/6] feat: added pre check to build --- Dockerfile | 2 ++ build.sh | 2 ++ options_tester.cjs | 21 +++++++++++++++++++++ options_tester.ts | 21 +++++++++++++++++++++ package.json | 4 ++-- 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 build.sh create mode 100644 options_tester.cjs create mode 100644 options_tester.ts diff --git a/Dockerfile b/Dockerfile index 6e2c7c75..f624cca6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,8 @@ COPY package.json package-lock.json ./ RUN npm install COPY ./vite.config.ts ./vite.demo.config.ts ./extensions.json ./tsconfig.json ./tsconfig.node.json ./ COPY ./packages ./packages +COPY ./options_tester.cjs ./options_tester.cjs + RUN VITE_TARGET_ENVIRONMENT=${TARGET_ENVIRONMENT} npm run build RUN VITE_TARGET_ENVIRONMENT=${TARGET_ENVIRONMENT} npm run build:demo diff --git a/build.sh b/build.sh new file mode 100644 index 00000000..5b10f837 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +tsc --resolveJsonModule --esModuleInterop options_tester.ts +mv options_tester.js options_tester.cjs \ No newline at end of file diff --git a/options_tester.cjs b/options_tester.cjs new file mode 100644 index 00000000..9fdfc808 --- /dev/null +++ b/options_tester.cjs @@ -0,0 +1,21 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var options_schema_json_1 = __importDefault(require("./packages/lib/src/interfaces/options.schema.json")); +var schemasafe_1 = require("@exodus/schemasafe"); +var options_json_1 = __importDefault(require("./packages/demo/public/options.json")); +console.log("Checking Lens options"); +var parse = (0, schemasafe_1.parser)(options_schema_json_1.default, { + includeErrors: true, + allErrors: true, +}); +var validJSON = parse(JSON.stringify(options_json_1.default)); +if (validJSON.valid === true) { + console.log("Options are valid"); +} +else if (typeof options_json_1.default === "object") { + console.error("Lens-Options are not conform with the JSON schema", validJSON.errors); + process.exit(1); +} diff --git a/options_tester.ts b/options_tester.ts new file mode 100644 index 00000000..296c6d26 --- /dev/null +++ b/options_tester.ts @@ -0,0 +1,21 @@ +import optionsSchema from "./packages/lib/src/interfaces/options.schema.json"; +import { parser } from "@exodus/schemasafe"; + +import options from "./packages/demo/public/options.json"; + +console.log("Checking Lens options"); + +const parse = parser(optionsSchema, { + includeErrors: true, + allErrors: true, +}); +const validJSON = parse(JSON.stringify(options)); +if (validJSON.valid === true) { + console.log("Options are valid"); +} else if (typeof options === "object") { + console.error( + "Lens-Options are not conform with the JSON schema", + validJSON.errors, + ); + process.exit(1); +} diff --git a/package.json b/package.json index 3740beb1..b7762a64 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "license": "MIT", "scripts": { "start": "npm run dev -s", - "dev": "vite --config vite.demo.config.ts", - "build": "vite build", + "dev": "node options_tester.cjs && vite --config vite.demo.config.ts", + "build": "node options_tester.cjs && vite build", "build:demo": "vite build --config vite.demo.config.ts", "preview": "vite preview --config vite.demo.config.ts", "check": "svelte-check --tsconfig ./tsconfig.json", From 31e89a8b5e817488b565f2a1a62d9530b5dafe45 Mon Sep 17 00:00:00 2001 From: Patrick Skowronek Date: Wed, 29 May 2024 10:29:19 +0200 Subject: [PATCH 6/6] fix: package.json scripts --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b7762a64..1151e188 100644 --- a/package.json +++ b/package.json @@ -28,11 +28,11 @@ "license": "MIT", "scripts": { "start": "npm run dev -s", - "dev": "node options_tester.cjs && vite --config vite.demo.config.ts", - "build": "node options_tester.cjs && vite build", - "build:demo": "vite build --config vite.demo.config.ts", + "dev": "vite --config vite.demo.config.ts", + "build": "vite build", + "build:demo": "node options_tester.cjs && vite build --config vite.demo.config.ts", "preview": "vite preview --config vite.demo.config.ts", - "check": "svelte-check --tsconfig ./tsconfig.json", + "check": "node options_tester.cjs && svelte-check --tsconfig ./tsconfig.json", "lint": "lint-staged", "watch": "rimraf dist && vite build --watch", "link": "wait-on dist/types.d.ts && cd dist/ && npm link",