diff --git a/e2e/visual/fixtures/empty.json b/e2e/visual/fixtures/empty.json
index 33f16810a..a3af70379 100644
--- a/e2e/visual/fixtures/empty.json
+++ b/e2e/visual/fixtures/empty.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../packages/form-json-schema/resources/schema.json",
"schemaVersion": 8,
"exporter": {
"name": "Camunda Web Modeler",
diff --git a/e2e/visual/fixtures/form.json b/e2e/visual/fixtures/form.json
index 0adcd9e59..ea7d92557 100644
--- a/e2e/visual/fixtures/form.json
+++ b/e2e/visual/fixtures/form.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../packages/form-json-schema/resources/schema.json",
"components": [
{
"key": "creditor",
@@ -132,13 +133,11 @@
"type": "image"
},
{
- "key": "submit",
"label": "Submit",
"type": "button"
},
{
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/e2e/visual/fixtures/groups.json b/e2e/visual/fixtures/groups.json
index 51d7061ba..5af65ff9d 100644
--- a/e2e/visual/fixtures/groups.json
+++ b/e2e/visual/fixtures/groups.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../packages/form-json-schema/resources/schema.json",
"schemaVersion": 11,
"exporter": {
"name": "Camunda Web Modeler",
diff --git a/package-lock.json b/package-lock.json
index 00215fedc..aea3bd305 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
"packages/*"
],
"devDependencies": {
+ "@apidevtools/json-schema-ref-parser": "^9.0.9",
"@axe-core/playwright": "^4.7.3",
"@babel/core": "^7.18.10",
"@babel/plugin-transform-react-jsx": "^7.14.5",
@@ -31,6 +32,8 @@
"@types/node": "^20.6.3",
"@types/sinon": "^10.0.0",
"@types/sinon-chai": "^3.2.5",
+ "ajv": "^8.12.0",
+ "ajv-errors": "^3.0.0",
"axe-core": "^4.8.2",
"babel-loader": "^9.0.0",
"babel-plugin-istanbul": "^6.1.1",
@@ -57,6 +60,7 @@
"lerna": "^6.0.0",
"mocha": "^10.0.0",
"mocha-test-container-support": "^0.2.0",
+ "mri": "^1.2.0",
"npm-run-all": "^4.1.5",
"preact": "10.5.14",
"puppeteer": "^21.0.0",
@@ -86,6 +90,36 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@apidevtools/json-schema-ref-parser": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
+ "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
+ "dev": true,
+ "dependencies": {
+ "@jsdevtools/ono": "^7.1.3",
+ "@types/json-schema": "^7.0.6",
+ "call-me-maybe": "^1.0.1",
+ "js-yaml": "^4.1.0"
+ }
+ },
+ "node_modules/@apidevtools/json-schema-ref-parser/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/@apidevtools/json-schema-ref-parser/node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
"node_modules/@axe-core/playwright": {
"version": "4.7.3",
"resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.7.3.tgz",
@@ -177,12 +211,13 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
- "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.22.5"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
@@ -228,12 +263,12 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
- "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.5",
+ "@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -371,22 +406,22 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
- "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
- "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"dependencies": {
- "@babel/template": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
@@ -528,9 +563,9 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
- "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5"
@@ -549,9 +584,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -596,13 +631,13 @@
}
},
"node_modules/@babel/highlight": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
- "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.22.5",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@@ -610,9 +645,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
- "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -2047,33 +2082,33 @@
}
},
"node_modules/@babel/template": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
- "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
- "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.5",
- "@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-function-name": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -2082,13 +2117,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
- "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -2221,6 +2256,10 @@
"resolved": "packages/form-js-viewer",
"link": true
},
+ "node_modules/@bpmn-io/form-json-schema": {
+ "resolved": "packages/form-json-schema",
+ "link": true
+ },
"node_modules/@bpmn-io/properties-panel": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/@bpmn-io/properties-panel/-/properties-panel-3.11.0.tgz",
@@ -2574,6 +2613,22 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@eslint/eslintrc/node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "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/@eslint/eslintrc/node_modules/argparse": {
"version": "2.0.1",
"dev": true,
@@ -2604,6 +2659,12 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/@eslint/eslintrc/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==",
+ "dev": true
+ },
"node_modules/@eslint/eslintrc/node_modules/type-fest": {
"version": "0.20.2",
"dev": true,
@@ -2767,6 +2828,12 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
+ "node_modules/@jsdevtools/ono": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
+ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
+ "dev": true
+ },
"node_modules/@lerna/add": {
"version": "6.1.0",
"dev": true,
@@ -6942,13 +7009,14 @@
}
},
"node_modules/ajv": {
- "version": "6.12.6",
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
@@ -6956,6 +7024,15 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/ajv-errors": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz",
+ "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==",
+ "dev": true,
+ "peerDependencies": {
+ "ajv": "^8.0.1"
+ }
+ },
"node_modules/ajv-formats": {
"version": "2.1.1",
"dev": true,
@@ -6972,34 +7049,6 @@
}
}
},
- "node_modules/ajv-formats/node_modules/ajv": {
- "version": "8.12.0",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ajv-formats/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/ajv-keywords": {
- "version": "3.5.2",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "ajv": "^6.9.1"
- }
- },
"node_modules/ansi-colors": {
"version": "4.1.1",
"dev": true,
@@ -7670,21 +7719,6 @@
"webpack": ">=5"
}
},
- "node_modules/babel-loader/node_modules/ajv": {
- "version": "8.12.0",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
"node_modules/babel-loader/node_modules/ajv-keywords": {
"version": "5.1.0",
"dev": true,
@@ -7696,11 +7730,6 @@
"ajv": "^8.8.2"
}
},
- "node_modules/babel-loader/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "dev": true,
- "license": "MIT"
- },
"node_modules/babel-loader/node_modules/schema-utils": {
"version": "4.0.0",
"dev": true,
@@ -8253,6 +8282,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/call-me-maybe": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
+ "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
+ "dev": true
+ },
"node_modules/camelcase": {
"version": "5.3.1",
"dev": true,
@@ -11039,6 +11074,22 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/eslint/node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "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/eslint/node_modules/ansi-styles": {
"version": "4.3.0",
"dev": true,
@@ -11192,6 +11243,12 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/eslint/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==",
+ "dev": true
+ },
"node_modules/eslint/node_modules/locate-path": {
"version": "6.0.0",
"dev": true,
@@ -11563,8 +11620,9 @@
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
@@ -13709,9 +13767,10 @@
"license": "MIT"
},
"node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "dev": true,
- "license": "MIT"
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -15176,6 +15235,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/ms": {
"version": "2.1.3",
"dev": true,
@@ -18659,6 +18727,37 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/schema-utils/node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "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/schema-utils/node_modules/ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "dev": true,
+ "peerDependencies": {
+ "ajv": "^6.9.1"
+ }
+ },
+ "node_modules/schema-utils/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==",
+ "dev": true
+ },
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -20917,6 +21016,11 @@
"packages/form-js-viewer/node_modules/min-dash": {
"version": "4.0.0",
"license": "MIT"
+ },
+ "packages/form-json-schema": {
+ "name": "@bpmn-io/form-json-schema",
+ "version": "1.4.0",
+ "license": "SEE LICENSE IN LICENSE"
}
},
"dependencies": {
@@ -20928,6 +21032,35 @@
"@jridgewell/trace-mapping": "^0.3.9"
}
},
+ "@apidevtools/json-schema-ref-parser": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
+ "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
+ "dev": true,
+ "requires": {
+ "@jsdevtools/ono": "^7.1.3",
+ "@types/json-schema": "^7.0.6",
+ "call-me-maybe": "^1.0.1",
+ "js-yaml": "^4.1.0"
+ },
+ "dependencies": {
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "requires": {
+ "argparse": "^2.0.1"
+ }
+ }
+ }
+ },
"@axe-core/playwright": {
"version": "4.7.3",
"resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.7.3.tgz",
@@ -20991,12 +21124,13 @@
}
},
"@babel/code-frame": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
- "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.22.5"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
}
},
"@babel/compat-data": {
@@ -21029,12 +21163,12 @@
}
},
"@babel/generator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
- "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"requires": {
- "@babel/types": "^7.22.5",
+ "@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -21142,19 +21276,19 @@
}
},
"@babel/helper-environment-visitor": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
- "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true
},
"@babel/helper-function-name": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
- "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"requires": {
- "@babel/template": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
@@ -21260,9 +21394,9 @@
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
- "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"requires": {
"@babel/types": "^7.22.5"
@@ -21275,9 +21409,9 @@
"dev": true
},
"@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true
},
"@babel/helper-validator-option": {
@@ -21310,20 +21444,20 @@
}
},
"@babel/highlight": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
- "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.22.5",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
- "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true
},
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
@@ -22271,42 +22405,42 @@
}
},
"@babel/template": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
- "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
}
},
"@babel/traverse": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
- "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.5",
- "@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-function-name": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
- "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"requires": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
@@ -22522,6 +22656,9 @@
}
}
},
+ "@bpmn-io/form-json-schema": {
+ "version": "file:packages/form-json-schema"
+ },
"@bpmn-io/properties-panel": {
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/@bpmn-io/properties-panel/-/properties-panel-3.11.0.tgz",
@@ -22834,6 +22971,18 @@
"strip-json-comments": "^3.1.1"
},
"dependencies": {
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
"argparse": {
"version": "2.0.1",
"dev": true
@@ -22852,6 +23001,12 @@
"argparse": "^2.0.1"
}
},
+ "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==",
+ "dev": true
+ },
"type-fest": {
"version": "0.20.2",
"dev": true
@@ -22967,6 +23122,12 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
+ "@jsdevtools/ono": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
+ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
+ "dev": true
+ },
"@lerna/add": {
"version": "6.1.0",
"dev": true,
@@ -25907,43 +26068,31 @@
}
},
"ajv": {
- "version": "6.12.6",
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
}
},
+ "ajv-errors": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz",
+ "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==",
+ "dev": true,
+ "requires": {}
+ },
"ajv-formats": {
"version": "2.1.1",
"dev": true,
"requires": {
"ajv": "^8.0.0"
- },
- "dependencies": {
- "ajv": {
- "version": "8.12.0",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
- "json-schema-traverse": {
- "version": "1.0.0",
- "dev": true
- }
}
},
- "ajv-keywords": {
- "version": "3.5.2",
- "dev": true,
- "requires": {}
- },
"ansi-colors": {
"version": "4.1.1",
"dev": true
@@ -26369,16 +26518,6 @@
"schema-utils": "^4.0.0"
},
"dependencies": {
- "ajv": {
- "version": "8.12.0",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
"ajv-keywords": {
"version": "5.1.0",
"dev": true,
@@ -26386,10 +26525,6 @@
"fast-deep-equal": "^3.1.3"
}
},
- "json-schema-traverse": {
- "version": "1.0.0",
- "dev": true
- },
"schema-utils": {
"version": "4.0.0",
"dev": true,
@@ -26752,6 +26887,12 @@
"get-intrinsic": "^1.0.2"
}
},
+ "call-me-maybe": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
+ "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
+ "dev": true
+ },
"camelcase": {
"version": "5.3.1",
"dev": true
@@ -28283,6 +28424,18 @@
"v8-compile-cache": "^2.0.3"
},
"dependencies": {
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
"ansi-styles": {
"version": "4.3.0",
"dev": true,
@@ -28371,6 +28524,12 @@
"argparse": "^2.0.1"
}
},
+ "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==",
+ "dev": true
+ },
"locate-path": {
"version": "6.0.0",
"dev": true,
@@ -28936,6 +29095,8 @@
},
"fast-json-stable-stringify": {
"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
},
"fast-levenshtein": {
@@ -30310,7 +30471,9 @@
"dev": true
},
"json-schema-traverse": {
- "version": "0.4.1",
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
"json-stable-stringify-without-jsonify": {
@@ -31302,6 +31465,12 @@
"version": "1.0.1",
"dev": true
},
+ "mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "dev": true
+ },
"ms": {
"version": "2.1.3",
"dev": true
@@ -33580,6 +33749,33 @@
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "dev": true,
+ "requires": {}
+ },
+ "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==",
+ "dev": true
+ }
}
},
"semver": {
diff --git a/package.json b/package.json
index 27a168d32..ba6053a3d 100644
--- a/package.json
+++ b/package.json
@@ -59,6 +59,7 @@
}
],
"devDependencies": {
+ "@apidevtools/json-schema-ref-parser": "^9.0.9",
"@axe-core/playwright": "^4.7.3",
"@babel/core": "^7.18.10",
"@babel/plugin-transform-react-jsx": "^7.14.5",
@@ -80,6 +81,8 @@
"@types/node": "^20.6.3",
"@types/sinon": "^10.0.0",
"@types/sinon-chai": "^3.2.5",
+ "ajv": "^8.12.0",
+ "ajv-errors": "^3.0.0",
"axe-core": "^4.8.2",
"babel-loader": "^9.0.0",
"babel-plugin-istanbul": "^6.1.1",
@@ -112,6 +115,7 @@
"raw-loader": "^4.0.2",
"rollup": "^3.0.0",
"rollup-plugin-copy": "^3.4.0",
+ "mri": "^1.2.0",
"sass": "^1.58.3",
"sass-loader": "^13.2.0",
"sinon": "^17.0.0",
diff --git a/packages/form-js-carbon-styles/test/spec/complex.json b/packages/form-js-carbon-styles/test/spec/complex.json
index 8536a545b..678ed45c0 100644
--- a/packages/form-js-carbon-styles/test/spec/complex.json
+++ b/packages/form-js-carbon-styles/test/spec/complex.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"text": "# Title 1\n## Title 2\n### Title 3\n#### Title 4\n##### Title 5\n###### Title 6\n\n[this is a link](https://camunda.com) and then comes [**another bold link**](https://bpmn.io) and then [_another italic link_](https://camunda.com)\n\n- list\n- list\n\n1. foo\n2. foo\n\nFoo _italic_ **bold**\n\n> Multiline code\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus auctor sodales pretium. Donec id volutpat quam, sit amet elementum lectus. \n\nInline `code`\n\n```\nMultiline code\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus auctor sodales pretium. Donec id volutpat quam, sit amet elementum lectus. \n```\n\n[Link](https://camunda.com)\n",
@@ -60,7 +61,7 @@
"label": "I am a read only textfield",
"type": "textfield",
"id": "Field_1r9b6p3",
- "key": "readonly-textfield",
+ "key": "readonly_textfield",
"description": "I am a read only textfield description",
"readonly": true,
"defaultValue": "value"
@@ -613,15 +614,13 @@
"action": "reset",
"label": "reset",
"type": "button",
- "id": "Field_1ydujqw",
- "key": "field_1yi6q4r"
+ "id": "Field_1ydujqw"
},
{
"action": "submit",
"label": "submit",
"type": "button",
- "id": "Field_1ydujqa",
- "key": "field_1yi6q4a"
+ "id": "Field_1ydujqa"
}
],
"type": "default",
diff --git a/packages/form-js-editor/test/spec/complex.json b/packages/form-js-editor/test/spec/complex.json
index 341c3c6f0..1e62652a1 100644
--- a/packages/form-js-editor/test/spec/complex.json
+++ b/packages/form-js-editor/test/spec/complex.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "columns",
diff --git a/packages/form-js-editor/test/spec/core/FormLayoutValidator.form.json b/packages/form-js-editor/test/spec/core/FormLayoutValidator.form.json
index 17addf337..2aa44b969 100644
--- a/packages/form-js-editor/test/spec/core/FormLayoutValidator.form.json
+++ b/packages/form-js-editor/test/spec/core/FormLayoutValidator.form.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../../form-json-schema/resources/schema.json",
"components": [
{
"id": "Textfield_1",
diff --git a/packages/form-js-editor/test/spec/defaultValues.json b/packages/form-js-editor/test/spec/defaultValues.json
index 5e83f2289..c01a9618a 100644
--- a/packages/form-js-editor/test/spec/defaultValues.json
+++ b/packages/form-js-editor/test/spec/defaultValues.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "text",
@@ -83,13 +84,11 @@
]
},
{
- "key": "submit",
"label": "Submit",
"type": "button"
},
{
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-js-editor/test/spec/features/properties-panel/PropertiesPanel.spec.js b/packages/form-js-editor/test/spec/features/properties-panel/PropertiesPanel.spec.js
index 3560f3e13..fe53a9a8a 100644
--- a/packages/form-js-editor/test/spec/features/properties-panel/PropertiesPanel.spec.js
+++ b/packages/form-js-editor/test/spec/features/properties-panel/PropertiesPanel.spec.js
@@ -282,7 +282,7 @@ describe('properties panel', function() {
it('entries', function() {
// given
- const field = schema.components.find(({ key }) => key === 'submit');
+ const field = schema.components.find(({ action }) => action === 'submit');
const result = createPropertiesPanel({
container,
diff --git a/packages/form-js-editor/test/spec/form-no-ids.json b/packages/form-js-editor/test/spec/form-no-ids.json
index 2a25b0a20..cea27a234 100644
--- a/packages/form-js-editor/test/spec/form-no-ids.json
+++ b/packages/form-js-editor/test/spec/form-no-ids.json
@@ -1,5 +1,6 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "text",
@@ -147,14 +148,12 @@
]
},
{
- "key": "submit",
"action": "submit",
"label": "Submit",
"type": "button"
},
{
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-js-editor/test/spec/form-rows.json b/packages/form-js-editor/test/spec/form-rows.json
index a55e6b3b9..6b269b01e 100644
--- a/packages/form-js-editor/test/spec/form-rows.json
+++ b/packages/form-js-editor/test/spec/form-rows.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"id": "Textfield_1",
diff --git a/packages/form-js-editor/test/spec/form.json b/packages/form-js-editor/test/spec/form.json
index 067eda3d3..1e388254e 100644
--- a/packages/form-js-editor/test/spec/form.json
+++ b/packages/form-js-editor/test/spec/form.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"id": "Form_1",
"type": "default",
"components": [
@@ -209,14 +210,12 @@
{
"id": "Button_1",
"action": "submit",
- "key": "submit",
"label": "Submit",
"type": "button"
},
{
"id": "Button_2",
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-js-editor/test/spec/other.json b/packages/form-js-editor/test/spec/other.json
index 666d5744a..6bfd8144f 100644
--- a/packages/form-js-editor/test/spec/other.json
+++ b/packages/form-js-editor/test/spec/other.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "text",
@@ -22,7 +23,6 @@
}
},
{
- "key": "submit",
"label": "Submit",
"type": "button"
}
diff --git a/packages/form-js-editor/test/spec/redundantValues.json b/packages/form-js-editor/test/spec/redundantValues.json
index a6d611baf..2de87da0d 100644
--- a/packages/form-js-editor/test/spec/redundantValues.json
+++ b/packages/form-js-editor/test/spec/redundantValues.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "redundantValues",
diff --git a/packages/form-js-playground/test/spec/form.json b/packages/form-js-playground/test/spec/form.json
index 2181435c5..70caeb4f5 100644
--- a/packages/form-js-playground/test/spec/form.json
+++ b/packages/form-js-playground/test/spec/form.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "text",
@@ -55,6 +56,7 @@
},
{
"type": "select",
+ "key": "selectMe",
"label": "Select me",
"valuesExpression": "=if isGood then [ \"good\" ] else [\"bad\"]"
},
diff --git a/packages/form-js-playground/test/spec/other-form.json b/packages/form-js-playground/test/spec/other-form.json
index e5d8f8f14..778c816bc 100644
--- a/packages/form-js-playground/test/spec/other-form.json
+++ b/packages/form-js-playground/test/spec/other-form.json
@@ -1,9 +1,9 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"action": "reset",
"id": "foo",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-js-playground/test/spec/rows-form.json b/packages/form-js-playground/test/spec/rows-form.json
index b6bf8dbf0..e119ac580 100644
--- a/packages/form-js-playground/test/spec/rows-form.json
+++ b/packages/form-js-playground/test/spec/rows-form.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "invoiceNumber",
diff --git a/packages/form-js-viewer/test/spec/appearance.json b/packages/form-js-viewer/test/spec/appearance.json
index fe10d5764..0c2c594f7 100644
--- a/packages/form-js-viewer/test/spec/appearance.json
+++ b/packages/form-js-viewer/test/spec/appearance.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "textfield",
diff --git a/packages/form-js-viewer/test/spec/complex-conditions.json b/packages/form-js-viewer/test/spec/complex-conditions.json
index 2e2014a9d..bcd666e94 100644
--- a/packages/form-js-viewer/test/spec/complex-conditions.json
+++ b/packages/form-js-viewer/test/spec/complex-conditions.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"label": "Complex display condition 1",
diff --git a/packages/form-js-viewer/test/spec/condition-errors.json b/packages/form-js-viewer/test/spec/condition-errors.json
index 8ec5ea215..87c57a49b 100644
--- a/packages/form-js-viewer/test/spec/condition-errors.json
+++ b/packages/form-js-viewer/test/spec/condition-errors.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"label": "Checkbox",
diff --git a/packages/form-js-viewer/test/spec/condition-external-variable.json b/packages/form-js-viewer/test/spec/condition-external-variable.json
index f49408047..2a2c5bb4c 100644
--- a/packages/form-js-viewer/test/spec/condition-external-variable.json
+++ b/packages/form-js-viewer/test/spec/condition-external-variable.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "amount",
@@ -14,6 +15,7 @@
},
{
"label": "Text Field",
+ "key": "textfield",
"type": "textfield",
"id": "Field",
"conditional": {
diff --git a/packages/form-js-viewer/test/spec/condition.json b/packages/form-js-viewer/test/spec/condition.json
index 8b52a0650..0836d859e 100644
--- a/packages/form-js-viewer/test/spec/condition.json
+++ b/packages/form-js-viewer/test/spec/condition.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "amount",
diff --git a/packages/form-js-viewer/test/spec/defaultValues.json b/packages/form-js-viewer/test/spec/defaultValues.json
index 9b5080ecc..bea0cd1f0 100644
--- a/packages/form-js-viewer/test/spec/defaultValues.json
+++ b/packages/form-js-viewer/test/spec/defaultValues.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "text",
@@ -154,13 +155,11 @@
]
},
{
- "key": "submit",
"label": "Submit",
"type": "button"
},
{
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-js-viewer/test/spec/descriptions.json b/packages/form-js-viewer/test/spec/descriptions.json
index 145f00388..5a6257fcb 100644
--- a/packages/form-js-viewer/test/spec/descriptions.json
+++ b/packages/form-js-viewer/test/spec/descriptions.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "textfield",
diff --git a/packages/form-js-viewer/test/spec/disabled.json b/packages/form-js-viewer/test/spec/disabled.json
index f2e185242..cbf829b9b 100644
--- a/packages/form-js-viewer/test/spec/disabled.json
+++ b/packages/form-js-viewer/test/spec/disabled.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"disabled": true,
@@ -39,13 +40,11 @@
"type": "textarea"
},
{
- "key": "submit",
"label": "Submit",
"type": "button"
},
{
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-js-viewer/test/spec/dynamic.json b/packages/form-js-viewer/test/spec/dynamic.json
index 9aae9b880..85e3ef697 100644
--- a/packages/form-js-viewer/test/spec/dynamic.json
+++ b/packages/form-js-viewer/test/spec/dynamic.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "product",
diff --git a/packages/form-js-viewer/test/spec/expression-external-variable.json b/packages/form-js-viewer/test/spec/expression-external-variable.json
index 8793e01a0..343f8649e 100644
--- a/packages/form-js-viewer/test/spec/expression-external-variable.json
+++ b/packages/form-js-viewer/test/spec/expression-external-variable.json
@@ -1,17 +1,15 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
- "label": "An image",
"source": "=logo",
"type": "image"
},
{
- "label": "An image with alt text",
"alt": "=alt",
"type": "image"
},
{
- "label": "Another image",
"alt": "This is just an image",
"type": "image"
},
diff --git a/packages/form-js-viewer/test/spec/focusables.json b/packages/form-js-viewer/test/spec/focusables.json
index c42949ad0..d033bcdb1 100644
--- a/packages/form-js-viewer/test/spec/focusables.json
+++ b/packages/form-js-viewer/test/spec/focusables.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"label": "Number",
diff --git a/packages/form-js-viewer/test/spec/form.json b/packages/form-js-viewer/test/spec/form.json
index 224d35afd..ccd049c8a 100644
--- a/packages/form-js-viewer/test/spec/form.json
+++ b/packages/form-js-viewer/test/spec/form.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "text",
@@ -137,13 +138,11 @@
"type": "image"
},
{
- "key": "submit",
"label": "Submit",
"type": "button"
},
{
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-js-viewer/test/spec/groups.json b/packages/form-js-viewer/test/spec/groups.json
index 859eb4aaa..5e3b30e44 100644
--- a/packages/form-js-viewer/test/spec/groups.json
+++ b/packages/form-js-viewer/test/spec/groups.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "text_root",
diff --git a/packages/form-js-viewer/test/spec/hidden-fields-conditional.json b/packages/form-js-viewer/test/spec/hidden-fields-conditional.json
index a363d1509..f3e97c207 100644
--- a/packages/form-js-viewer/test/spec/hidden-fields-conditional.json
+++ b/packages/form-js-viewer/test/spec/hidden-fields-conditional.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"label": "a",
diff --git a/packages/form-js-viewer/test/spec/hidden-fields-expression.json b/packages/form-js-viewer/test/spec/hidden-fields-expression.json
index b6db9e120..422e9d548 100644
--- a/packages/form-js-viewer/test/spec/hidden-fields-expression.json
+++ b/packages/form-js-viewer/test/spec/hidden-fields-expression.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"label": "a",
diff --git a/packages/form-js-viewer/test/spec/images.json b/packages/form-js-viewer/test/spec/images.json
index a0ba94ab6..099455d0d 100644
--- a/packages/form-js-viewer/test/spec/images.json
+++ b/packages/form-js-viewer/test/spec/images.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"source": "=logo_expression",
diff --git a/packages/form-js-viewer/test/spec/labels.json b/packages/form-js-viewer/test/spec/labels.json
index 24f0528a6..cd1968325 100644
--- a/packages/form-js-viewer/test/spec/labels.json
+++ b/packages/form-js-viewer/test/spec/labels.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "textfield",
diff --git a/packages/form-js-viewer/test/spec/other.json b/packages/form-js-viewer/test/spec/other.json
index 666d5744a..6bfd8144f 100644
--- a/packages/form-js-viewer/test/spec/other.json
+++ b/packages/form-js-viewer/test/spec/other.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "text",
@@ -22,7 +23,6 @@
}
},
{
- "key": "submit",
"label": "Submit",
"type": "button"
}
diff --git a/packages/form-js-viewer/test/spec/readonly-expression.json b/packages/form-js-viewer/test/spec/readonly-expression.json
index 32f5a55d7..484957d3d 100644
--- a/packages/form-js-viewer/test/spec/readonly-expression.json
+++ b/packages/form-js-viewer/test/spec/readonly-expression.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "amount",
diff --git a/packages/form-js-viewer/test/spec/rows.json b/packages/form-js-viewer/test/spec/rows.json
index 69a5f40df..5fbd54048 100644
--- a/packages/form-js-viewer/test/spec/rows.json
+++ b/packages/form-js-viewer/test/spec/rows.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"id": "Textfield_1",
diff --git a/packages/form-js-viewer/test/spec/ships-example.json b/packages/form-js-viewer/test/spec/ships-example.json
index fa721e0b4..5f53868f4 100644
--- a/packages/form-js-viewer/test/spec/ships-example.json
+++ b/packages/form-js-viewer/test/spec/ships-example.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"text": "#### Ship Name:\n {{shipsForSale[item.name = selectedShip].name}}\n#### Ship Description: \n {{shipsForSale[item.name = selectedShip].description}}\n#### Ship Price: \n {{shipsForSale[item.name = selectedShip].purchasePrice}}\n#### Frame:\n {{shipsForSale[item.name = selectedShip].frame.name}}\n#### Reactor:\n {{shipsForSale[item.name = selectedShip].reactor.name}}\n#### Engine:\n {{shipsForSale[item.name = selectedShip].engine.name}}\n#### Moduels:\n {{shipsForSale[item.name = selectedShip].modules.name}}\n",
diff --git a/packages/form-js-viewer/test/spec/stress.json b/packages/form-js-viewer/test/spec/stress.json
index 757c3bd65..0fc7b5d77 100644
--- a/packages/form-js-viewer/test/spec/stress.json
+++ b/packages/form-js-viewer/test/spec/stress.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"id": "Form_1",
"type": "default",
"components": [
@@ -19,14 +20,12 @@
{
"id": "Field_11",
"action": "submit",
- "key": "submit",
"label": "Submit",
"type": "button"
},
{
"id": "Field_12",
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-js-viewer/test/spec/template-variable-complex.json b/packages/form-js-viewer/test/spec/template-variable-complex.json
index 69a3d088d..d6ea896ca 100644
--- a/packages/form-js-viewer/test/spec/template-variable-complex.json
+++ b/packages/form-js-viewer/test/spec/template-variable-complex.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"text": "ConditionalExample: {{#if value > minimum}} Display conditionally {{display.subdisplay}} {{/if}}",
diff --git a/packages/form-js-viewer/test/spec/template-variable.json b/packages/form-js-viewer/test/spec/template-variable.json
index 91302b137..dcde6ffd2 100644
--- a/packages/form-js-viewer/test/spec/template-variable.json
+++ b/packages/form-js-viewer/test/spec/template-variable.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"text": "=myText",
diff --git a/packages/form-js-viewer/test/spec/text-template.json b/packages/form-js-viewer/test/spec/text-template.json
index 0886909bb..9043146c2 100644
--- a/packages/form-js-viewer/test/spec/text-template.json
+++ b/packages/form-js-viewer/test/spec/text-template.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"type": "text",
diff --git a/packages/form-js-viewer/test/spec/text.json b/packages/form-js-viewer/test/spec/text.json
index 955a32cfa..54b1d3781 100644
--- a/packages/form-js-viewer/test/spec/text.json
+++ b/packages/form-js-viewer/test/spec/text.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"schemaVersion": 1,
"exporter": {
"name": "form-js (https://demo.bpmn.io)",
diff --git a/packages/form-js-viewer/test/spec/util/GetSchemaVariables.spec.js b/packages/form-js-viewer/test/spec/util/GetSchemaVariables.spec.js
index d910bd6d6..1a5bb8c25 100644
--- a/packages/form-js-viewer/test/spec/util/GetSchemaVariables.spec.js
+++ b/packages/form-js-viewer/test/spec/util/GetSchemaVariables.spec.js
@@ -65,7 +65,7 @@ describe('util/getSchemaVariables', () => {
const variables = getSchemaVariables(conditionalSchema);
- expect(variables).to.eql([ 'externalVariable', 'amount' ]);
+ expect(variables).to.eql([ 'externalVariable', 'amount', 'textfield' ]);
});
@@ -73,7 +73,7 @@ describe('util/getSchemaVariables', () => {
const variables = getSchemaVariables(conditionalSchema, { inputs: false });
- expect(variables).to.eql([ 'amount' ]);
+ expect(variables).to.eql([ 'amount', 'textfield' ]);
});
diff --git a/packages/form-js-viewer/test/spec/validate.json b/packages/form-js-viewer/test/spec/validate.json
index f73f79284..68e0c29d8 100644
--- a/packages/form-js-viewer/test/spec/validate.json
+++ b/packages/form-js-viewer/test/spec/validate.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "number_expression",
diff --git a/packages/form-js-viewer/test/spec/valuesExpression.json b/packages/form-js-viewer/test/spec/valuesExpression.json
index ad9304424..924d6e65c 100644
--- a/packages/form-js-viewer/test/spec/valuesExpression.json
+++ b/packages/form-js-viewer/test/spec/valuesExpression.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"components": [
{
"key": "product",
diff --git a/packages/form-js/CHANGELOG.md b/packages/form-js/CHANGELOG.md
index ac2c30e5d..c71d33d37 100644
--- a/packages/form-js/CHANGELOG.md
+++ b/packages/form-js/CHANGELOG.md
@@ -6,6 +6,10 @@ All notable changes to [form-js](https://github.com/bpmn-io/form-js) are documen
___Note:__ Yet to be released changes appear here._
+### JSON Schema
+
+* `FEAT`: initial release, moved from https://github.com/pinussilvestrus/form-json-schema
+
## 1.4.0
### General
diff --git a/packages/form-js/test/spec/form.json b/packages/form-js/test/spec/form.json
index 14d51e75a..f4885188c 100644
--- a/packages/form-js/test/spec/form.json
+++ b/packages/form-js/test/spec/form.json
@@ -1,4 +1,5 @@
{
+ "$schema": "../../../form-json-schema/resources/schema.json",
"id": "Form_1",
"type": "default",
"components": [
@@ -178,14 +179,12 @@
{
"id": "Field_13",
"action": "submit",
- "key": "submit",
"label": "Submit",
"type": "button"
},
{
"id": "Field_14",
"action": "reset",
- "key": "reset",
"label": "Reset",
"type": "button"
}
diff --git a/packages/form-json-schema/.eslintrc b/packages/form-json-schema/.eslintrc
new file mode 100644
index 000000000..34238a56e
--- /dev/null
+++ b/packages/form-json-schema/.eslintrc
@@ -0,0 +1,3 @@
+{
+ "extends": "plugin:bpmn-io/node"
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/.gitignore b/packages/form-json-schema/.gitignore
new file mode 100644
index 000000000..fc4780852
--- /dev/null
+++ b/packages/form-json-schema/.gitignore
@@ -0,0 +1 @@
+resources
\ No newline at end of file
diff --git a/packages/form-json-schema/LICENSE b/packages/form-json-schema/LICENSE
new file mode 100644
index 000000000..05f751e37
--- /dev/null
+++ b/packages/form-json-schema/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2021-present Camunda Services GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in the
+Software without restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The source code responsible for displaying the bpmn.io project watermark that
+links back to https://bpmn.io as part of rendered diagrams MUST NOT be
+removed or changed. When this software is being used in a website or application,
+the watermark must stay fully visible and not visually overlapped by other elements.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/packages/form-json-schema/README.md b/packages/form-json-schema/README.md
new file mode 100644
index 000000000..e2b31de12
--- /dev/null
+++ b/packages/form-json-schema/README.md
@@ -0,0 +1,57 @@
+> ℹ️ This project is a development tool and not intended for production usage.
+
+# @bpmn-io/form-json-schema
+
+JSON Schema for [form-js](https://github.com/bpmn-io/form-js). The schema is built on top of and validated by [`json-schema@draft-07`](https://json-schema.org/draft-07/json-schema-release-notes.html).
+
+
+## Usage
+
+Set the `$schema` attribute to reference the [JSON Schema definition](./resources/schema.json).
+
+```js
+{
+ "$schema": "https://unpkg.com/@bpmn-io/form-json-schema/resources/schema.json",
+ "type": "default",
+ "schemaVersion": 11,
+ "components": []
+}
+```
+
+You can also use a specific version.
+
+```js
+"$schema": "https://unpkg.com/@bpmn-io/form-json-schema@0.2.0/resources/schema.json"
+```
+
+## Build and Run
+
+Prepare the project by installing all dependencies:
+
+```sh
+npm install
+```
+
+Bundle [the source schema files](./src) together
+
+```sh
+npm run build
+```
+
+Execute the following command to run the generated schema against the tests
+
+```sh
+npm run test
+```
+
+## Schema compatibility notice
+
+This schena is currently only compatible with following [form-js](https://github.com/bpmn-io/form-js) schema versions.
+
+| JSON schema version | form-js schema version |
+|---|---|
+| >= 0.2 | <= 12 |
+
+## License
+
+Use under the terms of the [bpmn.io license](http://bpmn.io/license).
diff --git a/packages/form-json-schema/package.json b/packages/form-json-schema/package.json
new file mode 100644
index 000000000..d1a1d90e0
--- /dev/null
+++ b/packages/form-json-schema/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "@bpmn-io/form-json-schema",
+ "version": "1.4.0",
+ "description": "JSON Schema for form-js",
+ "files": [
+ "resources"
+ ],
+ "scripts": {
+ "test": "mocha --reporter=spec --recursive test/spec",
+ "dev": "npm run test -- --watch",
+ "all": "run-s build test",
+ "build": "run-s build:error-messages build:schema",
+ "build:error-messages": "node tasks/generate-error-messages.js --input=./src/error-messages.json --output=./resources/error-messages.json",
+ "build:schema": "node tasks/generate-schema.js --input=./src/index.json --output=./resources/schema.json",
+ "prepare": "run-s build"
+ },
+ "license": "SEE LICENSE IN LICENSE",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/bpmn-io/form-js.git",
+ "directory": "packages/form-json-schema"
+ },
+ "author": {
+ "name": "bpmn.io contributors",
+ "url": "https://github.com/bpmn-io"
+ },
+ "keywords": [
+ "json-schema",
+ "form-js",
+ "forms"
+ ]
+}
diff --git a/packages/form-json-schema/src/defs/appearance.json b/packages/form-json-schema/src/defs/appearance.json
new file mode 100644
index 000000000..b6b71907b
--- /dev/null
+++ b/packages/form-json-schema/src/defs/appearance.json
@@ -0,0 +1,18 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/component/appearance",
+ "type": "object",
+ "description": "Changes the visual appearance of the form field.",
+ "properties": {
+ "prefixAdorner": {
+ "$id": "/#component/appearance/prefixAdorner",
+ "type": "string",
+ "description": "Adds an appendage before the input."
+ },
+ "suffixAdorner": {
+ "$id": "/#component/appearance/suffixAdorner",
+ "type": "string",
+ "description": "Adds an appendage after the input."
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/component.json b/packages/form-json-schema/src/defs/component.json
new file mode 100644
index 000000000..3a9e4c73d
--- /dev/null
+++ b/packages/form-json-schema/src/defs/component.json
@@ -0,0 +1,235 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/component",
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "rules/rules-required-properties.json"
+ },
+ {
+ "$ref": "rules/rules-allowed-properties.json"
+ },
+ {
+ "$ref": "rules/rules-defaultValue-type.json"
+ }
+ ],
+ "properties": {
+ "type": {
+ "$id": "#/component/type",
+ "$ref": "type.json"
+ },
+ "id": {
+ "$id": "#/component/id",
+ "description": "The id of a form field.",
+ "type": "string"
+ },
+ "label": {
+ "$id": "#/component/label",
+ "description": "Label displayed on top of the form field.",
+ "type": "string"
+ },
+ "description": {
+ "$id": "#/component/description",
+ "description": "Description provided below the form field.",
+ "type": "string"
+ },
+ "key": {
+ "$id": "#/component/key",
+ "description": "Binds the form field to a form variable. Can be a dot separated path.",
+ "type": "string",
+ "pattern": "^\\w+(\\.\\w+)*$"
+ },
+ "readonly": {
+ "$id": "#/component/readonly",
+ "description": "Makes the form field read only.",
+ "type": [
+ "boolean",
+ "string"
+ ]
+ },
+ "disabled": {
+ "$id": "#/component/disabled",
+ "description": "Disables the form field.",
+ "type": [
+ "boolean",
+ "string"
+ ]
+ },
+ "text": {
+ "$id": "#/component/text",
+ "description": "Text content of a text view. Either an expression, plain text, or templating syntax.",
+ "type": "string"
+ },
+ "defaultValue": {
+ "$id": "#/component/defaultValue",
+ "description": "Provides a default value for the form field in case no input data exists for the given key.",
+ "type": [ "string", "boolean", "number", "array" ]
+ },
+ "action": {
+ "$id": "#/component/action",
+ "description": "A button can either trigger a submit or a reset action. Defaults to submit.",
+ "default": "submit",
+ "type": "string",
+ "enum": [
+ "submit",
+ "reset"
+ ]
+ },
+ "source": {
+ "$id": "#/component/source",
+ "description": "Specifies the image source via expression or static value (hyperlink or data URI).",
+ "type": "string"
+ },
+ "alt": {
+ "$id": "#/component/alt",
+ "description": "Provides an alternative text to the image in case it cannot be displayed.",
+ "type": "string"
+ },
+ "subtype": {
+ "$id": "#/component/subtype",
+ "description": "Selects the type of the datetime component. This can either be date, time, or datetime. Defaults to date.",
+ "type": "string",
+ "default": "date",
+ "enum": [
+ "date",
+ "time",
+ "datetime"
+ ]
+ },
+ "dateLabel": {
+ "$id": "#/component/dateLabel",
+ "description": "Label displayed beside the date input field.",
+ "type": "string"
+ },
+ "timeLabel": {
+ "$id": "#/component/timeLabel",
+ "description": "Label displayed beside the time input field.",
+ "type": "string"
+ },
+ "use24h": {
+ "$id": "#/component/use24h",
+ "description": "Enables 24-hour time format.",
+ "type": "boolean"
+ },
+ "timeSerializingFormat": {
+ "$id": "#/component/timeSerializingFormat",
+ "description": "Defines the time data format. This can either be utc_offset, utc_normalized, or no_timezone.",
+ "type": "string",
+ "enum": [
+ "utc_offset",
+ "utc_normalized",
+ "no_timezone"
+ ]
+ },
+ "timeInterval": {
+ "$id": "#/component/timeInterval",
+ "description": "Defines the steps of time that can be selected in the time input field.",
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 60
+ },
+ "disallowPassedDates": {
+ "$id": "#/component/disallowPassedDates",
+ "description": "Enables the restriction to not allow past dates.",
+ "type": "boolean"
+ },
+ "increment": {
+ "$id": "#/component/increment",
+ "description": "Defines the increment between valid field value.",
+ "type": [
+ "number",
+ "string"
+ ]
+ },
+ "decimalDigits": {
+ "$id": "#/component/decimalDigits",
+ "description": "Defines the maximum number of digits after the decimal..",
+ "type": "integer"
+ },
+ "serializeToString": {
+ "$id": "#/component/serializeToString",
+ "description": "Configures the output format of the value. This enables unlimited precision digits.",
+ "type": "boolean"
+ },
+ "searchable": {
+ "$id": "#/component/searchable",
+ "description": "Allows the select entries to be searched via keyboard.",
+ "type": "boolean"
+ },
+ "valuesKey": {
+ "$id": "#/component/valuesKey",
+ "description": "Form fields can be configured with an options source defining the individual choices the select provides.",
+ "type": "string",
+ "pattern": "^[^\\s]*$"
+ },
+ "valuesExpression": {
+ "$id": "#/component/valuesExpression",
+ "description": "Form fields can be configured with a FEEL expression defining the individual choices the select provides.",
+ "type": "string"
+ },
+ "height": {
+ "$id": "#/component/height",
+ "description": "The height of the spacer component.",
+ "type": "number"
+ },
+ "components": {
+ "type": "array",
+ "$id": "#/component/components",
+ "description": "List of form field children.",
+ "items": {
+ "type": "object",
+ "$ref": "component.json",
+ "$id": "#/components/component"
+ }
+ },
+ "path": {
+ "$id": "#/component/path",
+ "description": "Assigns a path that maps form field children into a data object. Can be a dot separated path.",
+ "type": "string",
+ "pattern": "^(\\w+(\\.\\w+)*)*$"
+ },
+ "showOutline": {
+ "$id": "#/component/showOutline",
+ "description": "Groups and dynamic lists can have a visual outline.",
+ "type": "boolean"
+ },
+ "verticalAlignment": {
+ "$id": "#/component/verticalAlignment",
+ "description": "Groups and dynamic lists can be vertical aligned.",
+ "type": "string",
+ "default": "start",
+ "enum": [
+ "start",
+ "center",
+ "end"
+ ]
+ },
+ "validate": {
+ "$id": "#/component/validate",
+ "$ref": "validate.json"
+ },
+ "layout": {
+ "$id": "#/component/layout",
+ "$ref": "layout.json"
+ },
+ "values": {
+ "$id": "#/component/values",
+ "$ref": "values.json"
+ },
+ "appearance": {
+ "$id": "#/component/appearance",
+ "$ref": "appearance.json"
+ },
+ "conditional": {
+ "$id": "#/component/conditional",
+ "$ref": "conditional.json"
+ },
+ "properties": {
+ "$id": "#/component/properties",
+ "$ref": "properties.json"
+ }
+ },
+ "required": [
+ "type"
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/conditional.json b/packages/form-json-schema/src/defs/conditional.json
new file mode 100644
index 000000000..d2d45dd9f
--- /dev/null
+++ b/packages/form-json-schema/src/defs/conditional.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/component/conditional",
+ "type": "object",
+ "description": "Information of a form field related to conditional rendering.",
+ "properties": {
+ "hide": {
+ "$id": "/#component/conditional/hide",
+ "type": [
+ "string",
+ "boolean"
+ ],
+ "description": "Expression to hide the form field."
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/examples/components.json b/packages/form-json-schema/src/defs/examples/components.json
new file mode 100644
index 000000000..6e39215d2
--- /dev/null
+++ b/packages/form-json-schema/src/defs/examples/components.json
@@ -0,0 +1,147 @@
+{
+ "examples": [
+ [
+ {
+ "text": "Create a text",
+ "type": "text"
+ }
+ ],
+ [
+ {
+ "label": "Create a text field",
+ "type": "textfield",
+ "key": "textfield"
+ }
+ ],
+ [
+ {
+ "label": "Create a number field",
+ "type": "number",
+ "key": "number"
+ }
+ ],
+ [
+ {
+ "label": "Create a check box",
+ "type": "checkbox",
+ "key": "checkbox"
+ }
+ ],
+ [
+ {
+ "label": "Create a check list",
+ "values": [
+ {
+ "label": "Option 1",
+ "value": "option_1"
+ },
+ {
+ "label": "Option 2",
+ "value": "option_2"
+ }
+ ],
+ "type": "checklist",
+ "key": "checklist"
+ }
+ ],
+ [
+ {
+ "label": "Create a tag list",
+ "values": [
+ {
+ "label": "Option 1",
+ "value": "option_1"
+ },
+ {
+ "label": "Option 2",
+ "value": "option_2"
+ }
+ ],
+ "type": "taglist",
+ "key": "taglist"
+ }
+ ],
+ [
+ {
+ "label": "Create a radio button",
+ "values": [
+ {
+ "label": "Option 1",
+ "value": "option_1"
+ },
+ {
+ "label": "Option 2",
+ "value": "option_2"
+ }
+ ],
+ "type": "radio",
+ "key": "radio"
+ }
+ ],
+ [
+ {
+ "label": "Create a select",
+ "values": [
+ {
+ "label": "Option 1",
+ "value": "option_1"
+ },
+ {
+ "label": "Option 2",
+ "value": "option_2"
+ }
+ ],
+ "type": "select",
+ "key": "select"
+ }
+ ],
+ [
+ {
+ "alt": "Create an image",
+ "type": "image"
+ }
+ ],
+ [
+ {
+ "label": "Create a text area",
+ "type": "textarea",
+ "key": "textarea"
+ }
+ ],
+ [
+ {
+ "dateLabel": "Create a date time picker",
+ "subtype": "date",
+ "type": "datetime",
+ "key": "date"
+ }
+ ],
+ [
+ {
+ "type": "spacer",
+ "height": 60
+ }
+ ],
+ [
+ {
+ "label": "Create a button",
+ "type": "button",
+ "action": "submit"
+ }
+ ],
+ [
+ {
+ "label": "Create a group",
+ "type": "group",
+ "components": []
+ }
+ ],
+ [
+ {
+ "label": "Create a dynamic list",
+ "type": "dymamiclist",
+ "components": []
+ }
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/exporter.json b/packages/form-json-schema/src/defs/exporter.json
new file mode 100644
index 000000000..fa73ac356
--- /dev/null
+++ b/packages/form-json-schema/src/defs/exporter.json
@@ -0,0 +1,18 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/exporter",
+ "description": "The exporter tool of a form",
+ "type": "object",
+ "properties": {
+ "name": {
+ "$id": "#/exporter/name",
+ "description": "The name of the exporter tool",
+ "type": "string"
+ },
+ "version": {
+ "$id": "#/exporter/version",
+ "description": "The version of the exporter tool",
+ "type": "string"
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/field-types/containers.json b/packages/form-json-schema/src/defs/field-types/containers.json
new file mode 100644
index 000000000..50abfc5d1
--- /dev/null
+++ b/packages/form-json-schema/src/defs/field-types/containers.json
@@ -0,0 +1,13 @@
+{
+ "properties": {
+ "type": {
+ "enum": [
+ "group",
+ "dynamiclist"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/field-types/inputs.json b/packages/form-json-schema/src/defs/field-types/inputs.json
new file mode 100644
index 000000000..7353e5682
--- /dev/null
+++ b/packages/form-json-schema/src/defs/field-types/inputs.json
@@ -0,0 +1,20 @@
+{
+ "properties": {
+ "type": {
+ "enum": [
+ "checkbox",
+ "checklist",
+ "datetime",
+ "number",
+ "radio",
+ "select",
+ "taglist",
+ "textfield",
+ "textarea"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/field-types/multi-inputs.json b/packages/form-json-schema/src/defs/field-types/multi-inputs.json
new file mode 100644
index 000000000..d22b77fef
--- /dev/null
+++ b/packages/form-json-schema/src/defs/field-types/multi-inputs.json
@@ -0,0 +1,15 @@
+{
+ "properties": {
+ "type": {
+ "enum": [
+ "checklist",
+ "radio",
+ "select",
+ "taglist"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/layout.json b/packages/form-json-schema/src/defs/layout.json
new file mode 100644
index 000000000..86e6ab870
--- /dev/null
+++ b/packages/form-json-schema/src/defs/layout.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/component/layout",
+ "type": "object",
+ "description": "Layout related information of a form field.",
+ "properties": {
+ "row": {
+ "$id": "/#component/layout/row",
+ "type": [ "string", "null" ],
+ "description": "Row in which a form field is placed."
+ },
+ "columns": {
+ "$id": "/#component/validate/columns",
+ "type": [ "integer", "null" ],
+ "description": "Space the field will use inside its row. No value means it will automatically adjust to available space in the row.",
+ "minimum": 2,
+ "maximum": 16
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/properties.json b/packages/form-json-schema/src/defs/properties.json
new file mode 100644
index 000000000..b6476dd9e
--- /dev/null
+++ b/packages/form-json-schema/src/defs/properties.json
@@ -0,0 +1,6 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/component/properties",
+ "type": "object",
+ "description": "Custom properties of a form field."
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/rules/rules-allowed-properties.json b/packages/form-json-schema/src/defs/rules/rules-allowed-properties.json
new file mode 100644
index 000000000..2f4a38d62
--- /dev/null
+++ b/packages/form-json-schema/src/defs/rules/rules-allowed-properties.json
@@ -0,0 +1,338 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "allOf": [
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "const": "text"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "text": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "anyOf": [
+ {
+ "$ref": "../field-types/inputs.json"
+ },
+ {
+ "properties": {
+ "type": {
+ "const": "button"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ {
+ "$ref": "../field-types/containers.json"
+ }
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "label": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "$ref": "../field-types/inputs.json"
+ }
+ },
+ "then": {
+ "properties": {
+ "description": false,
+ "key": false,
+ "disabled": false,
+ "readonly": false,
+ "validate": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "const": "button"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "action": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "const": "image"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "source": false,
+ "alt": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "const": "datetime"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "subtype": false,
+ "dateLabel": false,
+ "timeLabel": false,
+ "use24h": false,
+ "timeSerializingFormat": false,
+ "timeInterval": false,
+ "disallowPassedDates": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "const": "number"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "increment": false,
+ "decimalDigits": false,
+ "serializeToString": false,
+ "validate": {
+ "properties": {
+ "min": false,
+ "max": false
+ }
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "const": "select"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "searchable": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "$ref": "../field-types/multi-inputs.json"
+ }
+ },
+ "then": {
+ "properties": {
+ "values": false,
+ "valuesKey": false,
+ "valuesExpression": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "const": "textfield"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "validate": {
+ "properties": {
+ "validationType": false,
+ "pattern": false
+ }
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "enum": [
+ "textfield",
+ "textarea"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "validate": {
+ "properties": {
+ "minLength": false,
+ "maxLength": false
+ }
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "enum": [
+ "textfield",
+ "number"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "appearance": {
+ "properties": {
+ "prefixAdorner": false,
+ "suffixAdorner": false
+ }
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "anyOf": [
+ {
+ "not": {
+ "$ref": "../field-types/inputs.json"
+ }
+ },
+ {
+ "allOf": [
+ {
+ "$ref": "../field-types/multi-inputs.json"
+ },
+ {
+ "properties": {
+ "valuesKey": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "valuesKey"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "then": {
+ "properties": {
+ "defaultValue": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "properties": {
+ "type": {
+ "const": "spacer"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ },
+ "then": {
+ "properties": {
+ "height": false
+ }
+ }
+ },
+ {
+ "if": {
+ "not": {
+ "$ref": "../field-types/containers.json"
+ }
+ },
+ "then": {
+ "properties": {
+ "path": false,
+ "showOutline": false,
+ "verticalAlignment": false,
+ "components": false
+ }
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/rules/rules-default.json b/packages/form-json-schema/src/defs/rules/rules-default.json
new file mode 100644
index 000000000..2aafb37b3
--- /dev/null
+++ b/packages/form-json-schema/src/defs/rules/rules-default.json
@@ -0,0 +1,24 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "const": "default"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "layout": false,
+ "conditional": false,
+ "properties": false
+ }
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/rules/rules-defaultValue-type.json b/packages/form-json-schema/src/defs/rules/rules-defaultValue-type.json
new file mode 100644
index 000000000..ef42ae3a9
--- /dev/null
+++ b/packages/form-json-schema/src/defs/rules/rules-defaultValue-type.json
@@ -0,0 +1,93 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "const": "checkbox"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "enum": [
+ "textfield",
+ "textarea",
+ "datetime",
+ "radio",
+ "select"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "defaultValue": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "const": "number"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "defaultValue": {
+ "type": [
+ "number",
+ "string"
+ ]
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "enum": [
+ "checklist",
+ "taglist"
+ ]
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "defaultValue": {
+ "type": "array"
+ }
+ }
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/rules/rules-required-properties.json b/packages/form-json-schema/src/defs/rules/rules-required-properties.json
new file mode 100644
index 000000000..1378794c3
--- /dev/null
+++ b/packages/form-json-schema/src/defs/rules/rules-required-properties.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "allOf": [
+ {
+ "if": {
+ "$ref": "../field-types/inputs.json"
+ },
+ "then": {
+ "required": [
+ "key"
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/type.json b/packages/form-json-schema/src/defs/type.json
new file mode 100644
index 000000000..b83c5e0f9
--- /dev/null
+++ b/packages/form-json-schema/src/defs/type.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/component/type",
+ "description": "The type of a form field.",
+ "enum": [
+ "textfield",
+ "number",
+ "datetime",
+ "textarea",
+ "checkbox",
+ "radio",
+ "select",
+ "checklist",
+ "taglist",
+ "image",
+ "text",
+ "button",
+ "spacer",
+ "group",
+ "dynamiclist",
+ "separator"
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/validate.json b/packages/form-json-schema/src/defs/validate.json
new file mode 100644
index 000000000..40da2c985
--- /dev/null
+++ b/packages/form-json-schema/src/defs/validate.json
@@ -0,0 +1,62 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/component/validate",
+ "type": "object",
+ "description": "Given that one of the following properties is set, the form will only submit when the respective condition is fulfilled. Otherwise, a validation error will be displayed.",
+ "properties": {
+ "required": {
+ "$id": "/#component/validate/required",
+ "type": "boolean",
+ "description": "Form field must contain a value."
+ },
+ "validationType": {
+ "$id": "/#component/validate/validationType",
+ "type": "string",
+ "description": "Use predefined validation patterns. Available options are: Email, Phone, and Custom (empty).",
+ "enum": [
+ "email",
+ "phone",
+ "custom",
+ "",
+ null
+ ]
+ },
+ "pattern": {
+ "$id": "/#component/validate/pattern",
+ "type": "string",
+ "description": "Form field value must match the provided RegEx pattern."
+ },
+ "minLength": {
+ "$id": "/#component/validate/minLength",
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Form field value must be at least the provided length."
+ },
+ "maxLength": {
+ "$id": "/#component/validate/maxLength",
+ "type": [
+ "integer",
+ "string"
+ ],
+ "description": "Form field value must be at most the provided length."
+ },
+ "min": {
+ "$id": "/#component/validate/min",
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Form field value must be at least the provided number."
+ },
+ "max": {
+ "$id": "/#component/validate/max",
+ "type": [
+ "number",
+ "string"
+ ],
+ "description": "Form field value must be at most the provided number."
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/defs/values.json b/packages/form-json-schema/src/defs/values.json
new file mode 100644
index 000000000..e6f7aecaa
--- /dev/null
+++ b/packages/form-json-schema/src/defs/values.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "#/component/values",
+ "type": "array",
+ "description": "Static options of a form field",
+ "items": {
+ "type": "object",
+ "properties": {
+ "label": {
+ "$id": "#/component/values/label",
+ "type": "string",
+ "description": "Label of the option"
+ },
+ "value": {
+ "$id": "#/component/values/value",
+ "type": "string",
+ "description": "Value of the option"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/src/error-messages.json b/packages/form-json-schema/src/error-messages.json
new file mode 100644
index 000000000..0637a088a
--- /dev/null
+++ b/packages/form-json-schema/src/error-messages.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/packages/form-json-schema/src/index.json b/packages/form-json-schema/src/index.json
new file mode 100644
index 000000000..326cdfeab
--- /dev/null
+++ b/packages/form-json-schema/src/index.json
@@ -0,0 +1,64 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "http://niklaskiefer.de/schema/form-js/1.0",
+ "title": "form-js JSON Schema",
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "src/defs/rules/rules-default.json"
+ }
+ ],
+ "properties": {
+ "type": {
+ "$id": "#/type",
+ "description": "The type of a form.",
+ "type": "string",
+ "const": "default"
+ },
+ "id": {
+ "$id": "#/id",
+ "description": "The id of a form.",
+ "type": "string"
+ },
+ "schemaVersion": {
+ "$id": "#/schemaVersion",
+ "description": "The schema version of a form",
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 12
+ },
+ "executionPlatform": {
+ "$id": "#/executionPlatform",
+ "description": "The target execution platform of a form",
+ "type": "string"
+ },
+ "executionPlatformVersion": {
+ "$id": "#/executionPlatformVersion",
+ "description": "The target execution platform version of a form",
+ "type": "string"
+ },
+ "exporter": {
+ "$id": "#/exporter",
+ "$ref": "src/defs/exporter.json"
+ },
+ "components": {
+ "type": "array",
+ "$id": "#/components",
+ "description": "List of form fields.",
+ "items": {
+ "type": "object",
+ "$ref": "src/defs/component.json",
+ "$id": "#/component"
+ },
+ "allOf": [
+ {
+ "$ref": "src/defs/examples/components.json"
+ }
+ ]
+ }
+ },
+ "required": [
+ "type",
+ "components"
+ ]
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/tasks/generate-error-messages.js b/packages/form-json-schema/tasks/generate-error-messages.js
new file mode 100644
index 000000000..690f8fe03
--- /dev/null
+++ b/packages/form-json-schema/tasks/generate-error-messages.js
@@ -0,0 +1,64 @@
+const util = require('util');
+
+const readFile = require('fs').readFileSync,
+ writeFile = require('fs').writeFileSync,
+ mkdir = require('fs').mkdirSync;
+
+const pathJoin = require('path').join,
+ dirname = require('path').dirname;
+
+const mri = require('mri');
+
+const argv = process.argv.slice(2);
+
+
+async function bundleErrors(errorMessages, path) {
+ return writeErrors(errorMessages, path);
+}
+
+
+function writeErrors(errorMessages, path) {
+ const filePath = pathJoin(path);
+
+ try {
+ mkdir(dirname(filePath));
+ } catch {
+
+ // directory may already exist
+ }
+
+ writeFile(filePath, JSON.stringify(errorMessages, 0, 2));
+
+ return filePath;
+}
+
+
+const {
+ input,
+ output
+} = mri(argv, {
+ alias: {
+ i: 'input',
+ o: 'output'
+ }
+});
+
+if (!input || !output) {
+ console.error('Arguments missing.');
+ console.error('Example: node tasks/generate-error-messages.js --input=./src/error-messages.json --output=./resources/error-messages.json');
+ process.exit(1);
+}
+
+bundleErrors(JSON.parse(readFile(input)), output);
+
+
+// helper /////////////
+
+// eslint-disable-next-line no-unused-vars
+function printNested(object) {
+ console.log(util.inspect(object, {
+ showHidden: false,
+ depth: null,
+ colors: true
+ }));
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/tasks/generate-schema.js b/packages/form-json-schema/tasks/generate-schema.js
new file mode 100644
index 000000000..c607c9c81
--- /dev/null
+++ b/packages/form-json-schema/tasks/generate-schema.js
@@ -0,0 +1,71 @@
+const util = require('util');
+const refParser = require('@apidevtools/json-schema-ref-parser');
+
+const readFile = require('fs').readFileSync,
+ writeFile = require('fs').writeFileSync,
+ mkdir = require('fs').mkdirSync;
+
+const pathJoin = require('path').join,
+ dirname = require('path').dirname;
+
+const mri = require('mri');
+
+const argv = process.argv.slice(2);
+
+
+async function bundleSchema(schema, path) {
+ try {
+ const plainSchema = await refParser.bundle(schema);
+ return writeSchema(plainSchema, path);
+ } catch (e) {
+ console.error(e);
+ process.exit(1);
+ }
+}
+
+
+function writeSchema(schema, path) {
+ const filePath = pathJoin(path);
+
+ try {
+ mkdir(dirname(filePath));
+ } catch {
+
+ // directory may already exist
+ }
+
+ writeFile(filePath, JSON.stringify(schema, 0, 2));
+
+ return filePath;
+}
+
+
+const {
+ input,
+ output
+} = mri(argv, {
+ alias: {
+ i: 'input',
+ o: 'output'
+ }
+});
+
+if (!input || !output) {
+ console.error('Arguments missing.');
+ console.error('Example: node tasks/generate-schema.js --input=./src/schema.json --output=./resources/schema.json');
+ process.exit(1);
+}
+
+bundleSchema(JSON.parse(readFile(input)), output);
+
+
+// helper /////////////
+
+// eslint-disable-next-line no-unused-vars
+function printNested(object) {
+ console.log(util.inspect(object, {
+ showHidden: false,
+ depth: null,
+ colors: true
+ }));
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/test/.eslintrc b/packages/form-json-schema/test/.eslintrc
new file mode 100644
index 000000000..2ef212354
--- /dev/null
+++ b/packages/form-json-schema/test/.eslintrc
@@ -0,0 +1,3 @@
+{
+ "extends": "plugin:bpmn-io/mocha"
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/action-not-allowed.js b/packages/form-json-schema/test/fixtures/action-not-allowed.js
new file mode 100644
index 000000000..321d1a5f2
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/action-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ action: 'submit'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/action',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/3/then/properties/action/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/3/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/alt-not-allowed.js b/packages/form-json-schema/test/fixtures/alt-not-allowed.js
new file mode 100644
index 000000000..0af75c2da
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/alt-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ alt: 'alt'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/alt',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/4/then/properties/alt/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/4/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/appearance-prefixAdorner-not-allowed.js b/packages/form-json-schema/test/fixtures/appearance-prefixAdorner-not-allowed.js
new file mode 100644
index 000000000..e0e8d17d2
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/appearance-prefixAdorner-not-allowed.js
@@ -0,0 +1,29 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textarea',
+ key: 'text',
+ appearance: {
+ prefixAdorner: 'prefix'
+ }
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/appearance/prefixAdorner',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/11/then/properties/appearance/properties/prefixAdorner/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/11/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/appearance-suffixAdorner-not-allowed.js b/packages/form-json-schema/test/fixtures/appearance-suffixAdorner-not-allowed.js
new file mode 100644
index 000000000..8e8893a14
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/appearance-suffixAdorner-not-allowed.js
@@ -0,0 +1,29 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textarea',
+ key: 'text',
+ appearance: {
+ suffixAdorner: 'suffix'
+ }
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/appearance/suffixAdorner',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/11/then/properties/appearance/properties/suffixAdorner/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/11/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/complex.js b/packages/form-json-schema/test/fixtures/complex.js
new file mode 100644
index 000000000..dc0b87e12
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/complex.js
@@ -0,0 +1,504 @@
+export const form = {
+ 'components': [
+ {
+ 'text': '# Title 1\n## Title 2\n### Title 3\n#### Title 4\n##### Title 5\n###### Title 6\n\n
\n\n- list\n- list\n\n1. foo\n2. foo\n\nFoo _italic_ **bold**\n\n> Multiline code\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus auctor sodales pretium. Donec id volutpat quam, sit amet elementum lectus. \n\nInline `code`\n\n```\nMultiline code\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus auctor sodales pretium. Donec id volutpat quam, sit amet elementum lectus. \n```\n\n[Link](https://camunda.com)\n',
+ 'type': 'text',
+ 'id': 'Field_1bbbwwg',
+ 'layout': {
+ 'row': 'Row_0lqavz4'
+ }
+ },
+ {
+ 'label': 'I am a texfield',
+ 'type': 'textfield',
+ 'id': 'Field_1l0t1m5',
+ 'key': 'textfield',
+ 'description': 'I am a texfield description',
+ 'validate': {
+ 'required': true
+ },
+ 'defaultValue': 'value',
+ 'layout': {
+ 'row': 'Row_14setyc',
+ 'columns': 10
+ }
+ },
+ {
+ 'label': 'I am a disabled texfield',
+ 'type': 'textfield',
+ 'id': 'Field_1r9b6p2',
+ 'key': 'disabled_textfield',
+ 'description': 'I am a disabled texfield description',
+ 'disabled': true,
+ 'defaultValue': 'value',
+ 'layout': {
+ 'row': 'Row_14setyc',
+ 'columns': 6
+ }
+ },
+ {
+ 'label': 'I am a read only texfield',
+ 'type': 'textfield',
+ 'id': 'Field_1r9b6p2',
+ 'key': 'readonly_textfield',
+ 'description': 'I am a read only texfield description',
+ 'readonly': true,
+ 'defaultValue': 'value',
+ 'layout': {
+ 'row': 'Row_14setyc',
+ 'columns': 6
+ }
+ },
+ {
+ 'label': 'I am a number field',
+ 'type': 'number',
+ 'id': 'Field_0ltb6av',
+ 'key': 'number_field',
+ 'description': 'I am a number field description',
+ 'validate': {
+ 'required': true
+ },
+ 'defaultValue': 1,
+ 'layout': {
+ 'row': 'Row_0m8z1wj',
+ 'columns': 8
+ }
+ },
+ {
+ 'label': 'I am a number field',
+ 'type': 'number',
+ 'id': 'Field_1t8wtoa',
+ 'key': 'disabled_number_field',
+ 'description': 'I am a disabled number field description',
+ 'disabled': true,
+ 'defaultValue': 1,
+ 'layout': {
+ 'row': 'Row_0m8z1wj',
+ 'columns': 8
+ }
+ },
+ {
+ 'label': 'I am checkbox',
+ 'type': 'checkbox',
+ 'id': 'Field_0jqueb7',
+ 'key': 'checkbox',
+ 'description': 'I am checkbox description',
+ 'defaultValue': false,
+ 'layout': {
+ 'row': 'Row_0l2l6gv'
+ }
+ },
+ {
+ 'label': 'I am disabled checked checkbox',
+ 'type': 'checkbox',
+ 'id': 'Field_1klmahz',
+ 'key': 'disabled_checked_checkbox',
+ 'disabled': true,
+ 'defaultValue': true,
+ 'description': 'I am disabled checked checkbox description',
+ 'layout': {
+ 'row': 'Row_0l2l6gv'
+ }
+ },
+ {
+ 'label': 'I am disabled checkbox',
+ 'type': 'checkbox',
+ 'id': 'Field_01h0ngn',
+ 'key': 'disabled_checkbox',
+ 'description': 'I am disabled checkbox description',
+ 'disabled': true,
+ 'layout': {
+ 'row': 'Row_0l2l6gv'
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ }
+ ],
+ 'label': 'I am checklist',
+ 'type': 'checklist',
+ 'id': 'Field_1d5nfix',
+ 'key': 'checklist',
+ 'description': 'I am checklist description',
+ 'layout': {
+ 'row': 'Row_0luakh3',
+ 'columns': 8
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_1'
+ }
+ ],
+ 'label': 'I am disabled checklist',
+ 'type': 'checklist',
+ 'id': 'Field_0l0y6cf',
+ 'key': 'disabled_checklist',
+ 'description': 'I am disabled checklist description',
+ 'disabled': true,
+ 'layout': {
+ 'row': 'Row_0luakh3',
+ 'columns': 8
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 3',
+ 'value': 'option_3'
+ }
+ ],
+ 'label': 'I am a taglist',
+ 'type': 'taglist',
+ 'id': 'Field_07zrh4q',
+ 'key': 'taglist',
+ 'description': 'I am a taglist description',
+ 'layout': {
+ 'row': 'Row_05mdvfz'
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 3',
+ 'value': 'option_3'
+ }
+ ],
+ 'label': 'I am a disabled taglist',
+ 'type': 'taglist',
+ 'id': 'Field_0hm9hgj',
+ 'key': 'disabled_taglist',
+ 'description': 'I am a disabled taglist description',
+ 'disabled': true,
+ 'layout': {
+ 'row': 'Row_0w9nbyn'
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 3',
+ 'value': 'option_3'
+ }
+ ],
+ 'label': 'I am a radio',
+ 'type': 'radio',
+ 'id': 'Field_0i46s34',
+ 'key': 'radio',
+ 'description': 'I am a radio description',
+ 'validate': {
+ 'required': true
+ },
+ 'layout': {
+ 'row': 'Row_0xpl64i'
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 3',
+ 'value': 'option_3'
+ }
+ ],
+ 'label': 'I am a disabled radio',
+ 'type': 'radio',
+ 'id': 'Field_110t1zy',
+ 'key': 'disabled_radio',
+ 'description': 'I am a disabled radio description',
+ 'validate': {
+ 'required': false
+ },
+ 'disabled': true,
+ 'layout': {
+ 'row': 'Row_0xpl64i'
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 3',
+ 'value': 'option_3'
+ }
+ ],
+ 'label': 'I am a select',
+ 'type': 'select',
+ 'id': 'Field_1iw4ekg',
+ 'key': 'select',
+ 'description': 'I am a select description',
+ 'validate': {
+ 'required': true
+ },
+ 'defaultValue': 'option_1',
+ 'layout': {
+ 'row': 'Row_084h2jt',
+ 'columns': 6
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 3',
+ 'value': 'option_3'
+ }
+ ],
+ 'label': 'I am a select',
+ 'type': 'select',
+ 'id': 'Field_06g19xn',
+ 'key': 'disabled_select',
+ 'description': 'I am a select description',
+ 'disabled': true,
+ 'defaultValue': 'option_2',
+ 'layout': {
+ 'row': 'Row_084h2jt',
+ 'columns': 10
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 3',
+ 'value': 'option_3'
+ }
+ ],
+ 'label': 'I am a searcheable select',
+ 'type': 'select',
+ 'id': 'Field_0g90q9s',
+ 'key': 'searcheable_select',
+ 'description': 'I am a searcheable select description',
+ 'searchable': true,
+ 'defaultValue': 'option_1',
+ 'validate': {
+ 'required': true
+ },
+ 'layout': {
+ 'row': 'Row_1cn6eez'
+ }
+ },
+ {
+ 'values': [
+ {
+ 'label': 'Option 1',
+ 'value': 'option_1'
+ },
+ {
+ 'label': 'Option 2',
+ 'value': 'option_2'
+ },
+ {
+ 'label': 'Option 3',
+ 'value': 'option_3'
+ }
+ ],
+ 'label': 'I am a disabled searcheable select',
+ 'type': 'select',
+ 'id': 'Field_06wzkll',
+ 'key': 'disabled_searcheable_select',
+ 'description': 'I am a disabled searcheable select description',
+ 'searchable': true,
+ 'defaultValue': 'option_2',
+ 'disabled': true,
+ 'layout': {
+ 'row': 'Row_0benm2m'
+ }
+ },
+ {
+ 'type': 'image',
+ 'id': 'Field_1mv8qs4',
+ 'alt': 'An placeholder',
+ 'source': 'https://via.placeholder.com/150C',
+ 'layout': {
+ 'row': 'Row_069d2ee'
+ }
+ },
+ {
+ 'label': 'I am a text area',
+ 'type': 'textarea',
+ 'id': 'Field_1f2xg0s',
+ 'key': 'textarea',
+ 'description': 'I am a text area description',
+ 'validate': {
+ 'required': true
+ },
+ 'layout': {
+ 'row': 'Row_16ga9gy'
+ }
+ },
+ {
+ 'label': 'I am a disabled text area',
+ 'type': 'textarea',
+ 'id': 'Field_1ae1pqq',
+ 'key': 'disabled_textarea',
+ 'description': 'I am a disabled text area description',
+ 'disabled': true,
+ 'layout': {
+ 'row': 'Row_00hoio8'
+ }
+ },
+ {
+ 'subtype': 'date',
+ 'dateLabel': 'I am a date field',
+ 'type': 'datetime',
+ 'id': 'Field_0h7fnn7',
+ 'key': 'date_field',
+ 'description': 'I am a date field description',
+ 'validate': {
+ 'required': true
+ },
+ 'layout': {
+ 'row': 'Row_0ld8s6t'
+ }
+ },
+ {
+ 'subtype': 'date',
+ 'dateLabel': 'I am a disabled date field',
+ 'type': 'datetime',
+ 'id': 'Field_09ff8mv',
+ 'key': 'disabled_date_field',
+ 'description': 'I am a disabled date field description',
+ 'disabled': true,
+ 'layout': {
+ 'row': 'Row_0b0kl2l'
+ }
+ },
+ {
+ 'label': 'I am an adorned field',
+ 'type': 'textfield',
+ 'id': 'Field_0k58wk0',
+ 'key': 'adorned_field',
+ 'description': 'I am an adorned field description',
+ 'appearance': {
+ 'prefixAdorner': 'camunda.com/'
+ },
+ 'layout': {
+ 'row': 'Row_0zjfzza'
+ }
+ },
+ {
+ 'label': 'I am an adorned field',
+ 'type': 'textfield',
+ 'id': 'Field_0k58wk01',
+ 'key': 'adorned_field1',
+ 'description': 'I am an adorned field description',
+ 'appearance': {
+ 'suffixAdorner': '@gmail.com'
+ },
+ 'layout': {
+ 'row': 'Row_1gcsy5f',
+ 'columns': 16
+ }
+ },
+ {
+ 'label': 'I am an adorned field',
+ 'type': 'textfield',
+ 'id': 'Field_0k58wk02',
+ 'key': 'adorned_field2',
+ 'description': 'I am an adorned field description',
+ 'appearance': {
+ 'prefixAdorner': '✨',
+ 'suffixAdorner': '🚀'
+ },
+ 'layout': {
+ 'row': 'Row_0xojlc6',
+ 'columns': null
+ }
+ },
+ {
+ 'type': 'separator',
+ 'id': 'Separator_1'
+ },
+ {
+ 'id': 'Spacer_1',
+ 'type': 'spacer',
+ 'height': 60
+ },
+ {
+ 'action': 'reset',
+ 'label': 'reset',
+ 'type': 'button',
+ 'id': 'Field_1ydujqw',
+ 'layout': {
+ 'row': 'Row_06ecoa2'
+ }
+ }
+ ],
+ 'type': 'default',
+ 'id': 'Form_1a82jj2',
+ 'executionPlatform': 'Camunda Cloud',
+ 'executionPlatformVersion': '8.2.0',
+ 'exporter': {
+ 'name': 'Camunda Modeler',
+ 'version': '5.10.0-dev'
+ },
+ 'schemaVersion': 11
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/components-not-allowed.js b/packages/form-json-schema/test/fixtures/components-not-allowed.js
new file mode 100644
index 000000000..eaf5a5a1c
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/components-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ components: []
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/components',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/14/then/properties/components/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/14/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/conditional-not-allowed.js b/packages/form-json-schema/test/fixtures/conditional-not-allowed.js
new file mode 100644
index 000000000..a65d9c9ca
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/conditional-not-allowed.js
@@ -0,0 +1,22 @@
+export const form = {
+ type: 'default',
+ components: [],
+ conditional: {}
+};
+
+export const errors = [
+ {
+ instancePath: '/conditional',
+ schemaPath: '#/allOf/0/allOf/0/then/properties/conditional/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '',
+ schemaPath: '#/allOf/0/allOf/0/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/dateLabel-not-allowed.js b/packages/form-json-schema/test/fixtures/dateLabel-not-allowed.js
new file mode 100644
index 000000000..b71a30145
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/dateLabel-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ dateLabel: 'date'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/dateLabel',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/then/properties/dateLabel/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/decimalDigits-not-allowed.js b/packages/form-json-schema/test/fixtures/decimalDigits-not-allowed.js
new file mode 100644
index 000000000..3b4ad99f9
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/decimalDigits-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ decimalDigits: 2
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/decimalDigits',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/then/properties/decimalDigits/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/defaultValue-no-array.js b/packages/form-json-schema/test/fixtures/defaultValue-no-array.js
new file mode 100644
index 000000000..4f0c4c4af
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/defaultValue-no-array.js
@@ -0,0 +1,28 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'checklist',
+ key: 'list',
+ defaultValue: 'foo',
+ values: []
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/defaultValue',
+ schemaPath: '#/properties/components/items/allOf/2/allOf/3/then/properties/defaultValue/type',
+ keyword: 'type',
+ params: { type: 'array' },
+ message: 'must be array'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/2/allOf/3/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/defaultValue-no-boolean.js b/packages/form-json-schema/test/fixtures/defaultValue-no-boolean.js
new file mode 100644
index 000000000..c93e48db0
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/defaultValue-no-boolean.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'checkbox',
+ key: 'checkbox',
+ defaultValue: 'foo'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/defaultValue',
+ schemaPath: '#/properties/components/items/allOf/2/allOf/0/then/properties/defaultValue/type',
+ keyword: 'type',
+ params: { type: 'boolean' },
+ message: 'must be boolean'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/2/allOf/0/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/defaultValue-no-string-or-number.js b/packages/form-json-schema/test/fixtures/defaultValue-no-string-or-number.js
new file mode 100644
index 000000000..dd4d92e9e
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/defaultValue-no-string-or-number.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'number',
+ key: 'number',
+ defaultValue: true
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/defaultValue',
+ schemaPath: '#/properties/components/items/allOf/2/allOf/2/then/properties/defaultValue/type',
+ keyword: 'type',
+ params: { type: [ 'number', 'string' ] },
+ message: 'must be number,string'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/2/allOf/2/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/defaultValue-no-string.js b/packages/form-json-schema/test/fixtures/defaultValue-no-string.js
new file mode 100644
index 000000000..39261c278
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/defaultValue-no-string.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textfield',
+ key: 'textfield',
+ defaultValue: 2
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/defaultValue',
+ schemaPath: '#/properties/components/items/allOf/2/allOf/1/then/properties/defaultValue/type',
+ keyword: 'type',
+ params: { type: 'string' },
+ message: 'must be string'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/2/allOf/1/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/defaultValue-not-allowed.js b/packages/form-json-schema/test/fixtures/defaultValue-not-allowed.js
new file mode 100644
index 000000000..4c712f647
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/defaultValue-not-allowed.js
@@ -0,0 +1,47 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ defaultValue: 'foo'
+ },
+ {
+ type: 'select',
+ key: 'select',
+ defaultValue: 'foo',
+ valuesKey: 'values'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/defaultValue',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/12/then/properties/defaultValue/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/12/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ },
+ {
+ instancePath: '/components/1/defaultValue',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/12/then/properties/defaultValue/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/1',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/12/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/description-not-allowed.js b/packages/form-json-schema/test/fixtures/description-not-allowed.js
new file mode 100644
index 000000000..f9574982c
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/description-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ description: 'text'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/description',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/then/properties/description/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/disabled-not-allowed.js b/packages/form-json-schema/test/fixtures/disabled-not-allowed.js
new file mode 100644
index 000000000..d81e2fd8f
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/disabled-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ disabled: true
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/disabled',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/then/properties/disabled/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/disallowPassedDates-not-allowed.js b/packages/form-json-schema/test/fixtures/disallowPassedDates-not-allowed.js
new file mode 100644
index 000000000..53cab16fe
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/disallowPassedDates-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ disallowPassedDates: true
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/disallowPassedDates',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/then/properties/disallowPassedDates/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/dynamiclists.js b/packages/form-json-schema/test/fixtures/dynamiclists.js
new file mode 100644
index 000000000..57035fb7a
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/dynamiclists.js
@@ -0,0 +1,36 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ 'id': 'id_dynamic_list',
+ 'path': 'dynamic',
+ 'label': 'Dynamic list',
+ 'type': 'dynamiclist',
+ 'components': []
+ },
+ {
+ 'id': 'id_dynamic_list_2',
+ 'path': 'dynamic2',
+ 'label': 'Dynamic list',
+ 'type': 'dynamiclist',
+ 'showOutline': true,
+ },
+ {
+ 'id': 'id_dynamic_list_parent',
+ 'path': 'dynamicParent',
+ 'label': 'Dynamic list parent',
+ 'type': 'dynamiclist',
+ 'components': [
+ {
+ 'id': 'id_dynamic_list_child',
+ 'path': 'dynamicChild',
+ 'label': 'Dynamic list child',
+ 'type': 'dynamiclist',
+ 'components': []
+ }
+ ]
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/expression-properties.js b/packages/form-json-schema/test/fixtures/expression-properties.js
new file mode 100644
index 000000000..ed8132cf1
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/expression-properties.js
@@ -0,0 +1,83 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textfield',
+ key: 'textfield_readonly_expression',
+ readonly: '=foo'
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_label_expression',
+ label: '=foo'
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_description_expression',
+ description: '=foo'
+ },
+ {
+ type: 'image',
+ alt: '=foo'
+ },
+ {
+ type: 'image',
+ source: '=foo'
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_prefix_expression',
+ appearance: {
+ prefix: '=foo'
+ }
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_suffix_expression',
+ appearance: {
+ suffix: '=foo'
+ }
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_hide_expression',
+ conditional: {
+ hide: '=foo'
+ }
+ },
+ {
+ type: 'text',
+ text: '=text'
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_minLength_expression',
+ validate: {
+ minLength: '=foo'
+ }
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_maxLength_expression',
+ validate: {
+ maxLength: '=foo'
+ }
+ },
+ {
+ type: 'number',
+ key: 'number_max_expression',
+ validate: {
+ max: '=foo'
+ }
+ },
+ {
+ type: 'number',
+ key: 'number_min_expression',
+ validate: {
+ min: '=foo'
+ }
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/groups.js b/packages/form-json-schema/test/fixtures/groups.js
new file mode 100644
index 000000000..866308e2c
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/groups.js
@@ -0,0 +1,87 @@
+export const form = {
+ 'components': [
+ {
+ 'key': 'text_root',
+ 'type': 'textfield'
+ },
+ {
+ 'alt': '=alt_root',
+ 'type': 'image'
+ },
+ {
+ 'label': 'flat group',
+ 'path': '',
+ 'type': 'group',
+ 'components': [
+ {
+ 'key': 'text_flat',
+ 'type': 'textfield'
+ },
+ {
+ 'alt': '=alt_flat',
+ 'type': 'image'
+ }
+ ]
+ },
+ {
+ 'label': 'nested group',
+ 'path': '',
+ 'type': 'group',
+ 'components': [
+ {
+ 'label': 'nested group',
+ 'path': '',
+ 'type': 'group',
+ 'components': [
+ {
+ 'key': 'text_nested',
+ 'type': 'textfield'
+ },
+ {
+ 'alt': '=alt_nested',
+ 'type': 'image'
+ }
+ ]
+ }
+ ]
+ },
+ {
+ 'label': 'pathed group',
+ 'path': 'pathed',
+ 'type': 'group',
+ 'components': [
+ {
+ 'key': 'text_pathed',
+ 'type': 'textfield'
+ },
+ {
+ 'alt': '=alt_pathed',
+ 'type': 'image'
+ }
+ ]
+ },
+ {
+ 'label': 'separated path group',
+ 'path': 'separated.path',
+ 'type': 'group',
+ 'components': [
+ {
+ 'key': 'text_separated',
+ 'type': 'textfield'
+ },
+ {
+ 'alt': '=alt_separated',
+ 'type': 'image'
+ }
+ ]
+ },
+ {
+ 'label': 'separated key textfield',
+ 'key': 'separated2.key',
+ 'type': 'textfield'
+ }
+ ],
+ 'type': 'default'
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/height-not-allowed.js b/packages/form-json-schema/test/fixtures/height-not-allowed.js
new file mode 100644
index 000000000..45ffb11b2
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/height-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ height: 60
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/height',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/13/then/properties/height/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/13/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/increment-not-allowed.js b/packages/form-json-schema/test/fixtures/increment-not-allowed.js
new file mode 100644
index 000000000..85bec45c5
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/increment-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ increment: '2'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/increment',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/then/properties/increment/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/increment.js b/packages/form-json-schema/test/fixtures/increment.js
new file mode 100644
index 000000000..ceabb4413
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/increment.js
@@ -0,0 +1,22 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'number',
+ key: 'increment_string',
+ increment: '20'
+ },
+ {
+ type: 'number',
+ key: 'increment_number',
+ increment: 20
+ },
+ {
+ type: 'number',
+ key: 'increment_float',
+ increment: 20.3
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/key-invalid.js b/packages/form-json-schema/test/fixtures/key-invalid.js
new file mode 100644
index 000000000..56a403ef7
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/key-invalid.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textfield',
+ key: 'textfield_1'
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_2.foo'
+ },
+ {
+ type: 'textfield',
+ key: 'textfield_3.'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/2/key',
+ schemaPath: '#/properties/components/items/properties/key/pattern',
+ keyword: 'pattern',
+ params: { pattern: '^\\w+(\\.\\w+)*$' },
+ message: 'must match pattern "^\\w+(\\.\\w+)*$"'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/key-not-allowed.js b/packages/form-json-schema/test/fixtures/key-not-allowed.js
new file mode 100644
index 000000000..51e6602c7
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/key-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ key: 'text'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/key',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/then/properties/key/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/label-not-allowed.js b/packages/form-json-schema/test/fixtures/label-not-allowed.js
new file mode 100644
index 000000000..1eb26eb74
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/label-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ label: 'text'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/label',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/1/then/properties/label/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/1/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/layout-empty-row.js b/packages/form-json-schema/test/fixtures/layout-empty-row.js
new file mode 100644
index 000000000..e57b7942e
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/layout-empty-row.js
@@ -0,0 +1,15 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textfield',
+ key: 'firstName',
+ layout: {
+ row: null,
+ columns: 12
+ }
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/layout-not-allowed.js b/packages/form-json-schema/test/fixtures/layout-not-allowed.js
new file mode 100644
index 000000000..896c18955
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/layout-not-allowed.js
@@ -0,0 +1,22 @@
+export const form = {
+ type: 'default',
+ components: [],
+ layout: {}
+};
+
+export const errors = [
+ {
+ instancePath: '/layout',
+ schemaPath: '#/allOf/0/allOf/0/then/properties/layout/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '',
+ schemaPath: '#/allOf/0/allOf/0/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/no-action.js b/packages/form-json-schema/test/fixtures/no-action.js
new file mode 100644
index 000000000..ece5f993b
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/no-action.js
@@ -0,0 +1,10 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'button'
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/no-key.js b/packages/form-json-schema/test/fixtures/no-key.js
new file mode 100644
index 000000000..a2db5e6d9
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/no-key.js
@@ -0,0 +1,28 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textfield'
+ },
+ {
+ type: 'text'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/0/allOf/0/then/required',
+ keyword: 'required',
+ params: { missingProperty: 'key' },
+ message: "must have required property 'key'"
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/0/allOf/0/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/no-subtype.js b/packages/form-json-schema/test/fixtures/no-subtype.js
new file mode 100644
index 000000000..b286eaa19
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/no-subtype.js
@@ -0,0 +1,11 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'datetime',
+ key: 'date'
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/no-values-property.js b/packages/form-json-schema/test/fixtures/no-values-property.js
new file mode 100644
index 000000000..e4b361d1d
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/no-values-property.js
@@ -0,0 +1,11 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'select',
+ key: 'select'
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/package.json b/packages/form-json-schema/test/fixtures/package.json
new file mode 100644
index 000000000..aead43de3
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/package.json
@@ -0,0 +1,3 @@
+{
+ "type": "module"
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/path-invalid.js b/packages/form-json-schema/test/fixtures/path-invalid.js
new file mode 100644
index 000000000..3ccc8c2ba
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/path-invalid.js
@@ -0,0 +1,31 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'group',
+ path: 'group_1'
+ },
+ {
+ type: 'group',
+ path: 'group_2.foo'
+ },
+ {
+ type: 'group',
+ path: 'group_3.'
+ },
+ {
+ type: 'group',
+ path: ''
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/2/path',
+ schemaPath: '#/properties/components/items/properties/path/pattern',
+ keyword: 'pattern',
+ params: { pattern: '^(\\w+(\\.\\w+)*)*$' },
+ message: 'must match pattern "^(\\w+(\\.\\w+)*)*$"'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/path-not-allowed.js b/packages/form-json-schema/test/fixtures/path-not-allowed.js
new file mode 100644
index 000000000..bc4237979
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/path-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ path: 'foobar'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/path',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/14/then/properties/path/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/14/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/properties-not-allowed.js b/packages/form-json-schema/test/fixtures/properties-not-allowed.js
new file mode 100644
index 000000000..eb93b02e7
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/properties-not-allowed.js
@@ -0,0 +1,22 @@
+export const form = {
+ type: 'default',
+ components: [],
+ properties: {}
+};
+
+export const errors = [
+ {
+ instancePath: '/properties',
+ schemaPath: '#/allOf/0/allOf/0/then/properties/properties/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '',
+ schemaPath: '#/allOf/0/allOf/0/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/readonly-not-allowed.js b/packages/form-json-schema/test/fixtures/readonly-not-allowed.js
new file mode 100644
index 000000000..bf9fff465
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/readonly-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ readonly: true
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/readonly',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/then/properties/readonly/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/schemaVersion-not-supported.js b/packages/form-json-schema/test/fixtures/schemaVersion-not-supported.js
new file mode 100644
index 000000000..24d64d137
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/schemaVersion-not-supported.js
@@ -0,0 +1,15 @@
+export const form = {
+ type: 'default',
+ components: [],
+ schemaVersion: 13
+};
+
+export const errors = [
+ {
+ instancePath: '/schemaVersion',
+ schemaPath: '#/properties/schemaVersion/maximum',
+ keyword: 'maximum',
+ params: { comparison: '<=', limit: 12 },
+ message: 'must be <= 12'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/searchable-not-allowed.js b/packages/form-json-schema/test/fixtures/searchable-not-allowed.js
new file mode 100644
index 000000000..f8204b7d0
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/searchable-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ searchable: true
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/searchable',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/7/then/properties/searchable/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/7/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/serializeToString-not-allowed.js b/packages/form-json-schema/test/fixtures/serializeToString-not-allowed.js
new file mode 100644
index 000000000..9b7dbe1f6
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/serializeToString-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ serializeToString: true
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/serializeToString',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/then/properties/serializeToString/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/showOutline-not-allowed.js b/packages/form-json-schema/test/fixtures/showOutline-not-allowed.js
new file mode 100644
index 000000000..962e704a3
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/showOutline-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ showOutline: false
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/showOutline',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/14/then/properties/showOutline/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/14/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/simple.js b/packages/form-json-schema/test/fixtures/simple.js
new file mode 100644
index 000000000..648d667e5
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/simple.js
@@ -0,0 +1,152 @@
+export const form = {
+ 'components': [
+ {
+ 'type': 'text',
+ 'text': "# Invoice\n\nLorem _ipsum_ __dolor__ `sit`.\n\nA list of BPMN symbols:\n\n* Start Event\n* Task\n\nLearn more about [forms](https://bpmn.io).\n \n \nThis [malicious link](javascript:throw onerror=alert,'some string',123,'haha') __should not work__."
+ },
+ {
+ 'key': 'creditor',
+ 'label': 'Creditor',
+ 'type': 'textfield',
+ 'validate': {
+ 'required': true
+ }
+ },
+ {
+ 'description': 'An invoice number in the format: C-123.',
+ 'key': 'invoiceNumber',
+ 'label': 'Invoice Number',
+ 'type': 'textfield',
+ 'validate': {
+ 'pattern': '^C-[0-9]+$'
+ }
+ },
+ {
+ 'key': 'amount',
+ 'label': 'Amount',
+ 'type': 'number',
+ 'validate': {
+ 'min': 0,
+ 'max': 1000
+ }
+ },
+ {
+ 'key': 'approved',
+ 'label': 'Approved',
+ 'type': 'checkbox'
+ },
+ {
+ 'key': 'approvedBy',
+ 'label': 'Approved By',
+ 'type': 'textfield'
+ },
+ {
+ 'key': 'approverComments',
+ 'label': 'Approver comments',
+ 'type': 'textarea'
+ },
+ {
+ 'key': 'product',
+ 'label': 'Product',
+ 'type': 'radio',
+ 'values': [
+ {
+ 'label': 'Camunda Platform',
+ 'value': 'camunda-platform'
+ },
+ {
+ 'label': 'Camunda Cloud',
+ 'value': 'camunda-cloud'
+ }
+ ]
+ },
+ {
+ 'key': 'mailto',
+ 'label': 'Email Summary To',
+ 'type': 'checklist',
+ 'values': [
+ {
+ 'label': 'Approver',
+ 'value': 'approver'
+ },
+ {
+ 'label': 'Manager',
+ 'value': 'manager'
+ },
+ {
+ 'label': 'Regional Manager',
+ 'value': 'regional-manager'
+ }
+ ]
+ },
+ {
+ 'key': 'language',
+ 'label': 'Language',
+ 'type': 'select',
+ 'values': [
+ {
+ 'label': 'German',
+ 'value': 'german'
+ },
+ {
+ 'label': 'English',
+ 'value': 'english'
+ }
+ ]
+ },
+ {
+ 'key': 'conversation',
+ 'type': 'datetime',
+ 'subtype': 'datetime',
+ 'dateLabel': 'Date of conversation',
+ 'timeLabel': 'Time of conversation',
+ 'timeSerializingFormat': 'utc_normalized',
+ 'timeInterval': 15,
+ 'use24h': false
+ },
+ {
+ 'key': 'tags',
+ 'label': 'Taglist',
+ 'type': 'taglist',
+ 'values': [
+ {
+ 'label': 'Tag 1',
+ 'value': 'tag1'
+ },
+ {
+ 'label': 'Tag 2',
+ 'value': 'tag2'
+ },
+ {
+ 'label': 'Tag 3',
+ 'value': 'tag3'
+ },
+ {
+ 'label': 'Tag 4',
+ 'value': 'tag4'
+ },
+ {
+ 'label': 'Tag 5',
+ 'value': 'tag5'
+ }
+ ]
+ },
+ {
+ 'alt': 'The bpmn.io logo',
+ 'type': 'image'
+ },
+ {
+ 'action': 'submit',
+ 'label': 'Submit',
+ 'type': 'button'
+ },
+ {
+ 'action': 'reset',
+ 'label': 'Reset',
+ 'type': 'button'
+ }
+ ],
+ 'type': 'default'
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/source-not-allowed.js b/packages/form-json-schema/test/fixtures/source-not-allowed.js
new file mode 100644
index 000000000..c82b9b5c2
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/source-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ source: 'image'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/source',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/4/then/properties/source/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/4/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/subtype-not-allowed.js b/packages/form-json-schema/test/fixtures/subtype-not-allowed.js
new file mode 100644
index 000000000..0a06ea237
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/subtype-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ subtype: 'date'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/subtype',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/then/properties/subtype/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/text-not-allowed.js b/packages/form-json-schema/test/fixtures/text-not-allowed.js
new file mode 100644
index 000000000..934ebd546
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/text-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'button',
+ text: 'Click me',
+ action: 'submit'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/text',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/0/then/properties/text/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/0/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/timeInterval-not-allowed.js b/packages/form-json-schema/test/fixtures/timeInterval-not-allowed.js
new file mode 100644
index 000000000..c4b8b6dd7
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/timeInterval-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ timeInterval: 2
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/timeInterval',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/then/properties/timeInterval/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/timeLabel-not-allowed.js b/packages/form-json-schema/test/fixtures/timeLabel-not-allowed.js
new file mode 100644
index 000000000..154a45b1e
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/timeLabel-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ timeLabel: 'date'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/timeLabel',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/then/properties/timeLabel/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/timeSerializingFormat-not-allowed.js b/packages/form-json-schema/test/fixtures/timeSerializingFormat-not-allowed.js
new file mode 100644
index 000000000..674b023ca
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/timeSerializingFormat-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ timeSerializingFormat: 'utc_offset'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/timeSerializingFormat',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/then/properties/timeSerializingFormat/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/use24h-not-allowed.js b/packages/form-json-schema/test/fixtures/use24h-not-allowed.js
new file mode 100644
index 000000000..e9bdf8cb8
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/use24h-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ use24h: true
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/use24h',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/then/properties/use24h/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/5/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/validate-max-not-allowed.js b/packages/form-json-schema/test/fixtures/validate-max-not-allowed.js
new file mode 100644
index 000000000..92316c59d
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/validate-max-not-allowed.js
@@ -0,0 +1,29 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textfield',
+ key: 'text',
+ validate: {
+ min: 2
+ }
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/validate/min',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/then/properties/validate/properties/min/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/validate-maxLength-not-allowed.js b/packages/form-json-schema/test/fixtures/validate-maxLength-not-allowed.js
new file mode 100644
index 000000000..131c6030e
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/validate-maxLength-not-allowed.js
@@ -0,0 +1,29 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'number',
+ key: 'number',
+ validate: {
+ maxLength: 2
+ }
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/validate/maxLength',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/10/then/properties/validate/properties/maxLength/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/10/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/validate-min-not-allowed.js b/packages/form-json-schema/test/fixtures/validate-min-not-allowed.js
new file mode 100644
index 000000000..2802454f8
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/validate-min-not-allowed.js
@@ -0,0 +1,29 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textfield',
+ key: 'text',
+ validate: {
+ max: 2
+ }
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/validate/max',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/then/properties/validate/properties/max/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/6/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/validate-minLength-not-allowed.js b/packages/form-json-schema/test/fixtures/validate-minLength-not-allowed.js
new file mode 100644
index 000000000..6f0a77d8a
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/validate-minLength-not-allowed.js
@@ -0,0 +1,29 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'number',
+ key: 'number',
+ validate: {
+ minLength: 2
+ }
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/validate/minLength',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/10/then/properties/validate/properties/minLength/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/10/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/validate-not-allowed.js b/packages/form-json-schema/test/fixtures/validate-not-allowed.js
new file mode 100644
index 000000000..9241d1c15
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/validate-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ validate: {}
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/validate',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/then/properties/validate/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/2/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/validate-pattern-not-allowed.js b/packages/form-json-schema/test/fixtures/validate-pattern-not-allowed.js
new file mode 100644
index 000000000..17cce7d66
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/validate-pattern-not-allowed.js
@@ -0,0 +1,29 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'number',
+ key: 'number',
+ validate: {
+ pattern: '^[0-9]+$'
+ }
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/validate/pattern',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/9/then/properties/validate/properties/pattern/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/9/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/validate-validationType-not-allowed.js b/packages/form-json-schema/test/fixtures/validate-validationType-not-allowed.js
new file mode 100644
index 000000000..fa0936971
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/validate-validationType-not-allowed.js
@@ -0,0 +1,29 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'number',
+ key: 'number',
+ validate: {
+ validationType: 'email'
+ }
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/validate/validationType',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/9/then/properties/validate/properties/validationType/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/9/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/validate-validationType.js b/packages/form-json-schema/test/fixtures/validate-validationType.js
new file mode 100644
index 000000000..5ab1436ae
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/validate-validationType.js
@@ -0,0 +1,40 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'textfield',
+ key: 'field_email',
+ validate: {
+ validationType: 'email'
+ }
+ },
+ {
+ type: 'textfield',
+ key: 'field_phone',
+ validate: {
+ validationType: 'phone'
+ }
+ },
+ {
+ type: 'textfield',
+ key: 'field_custom',
+ validate: {
+ validationType: 'custom'
+ }
+ },
+ {
+ type: 'textfield',
+ key: 'field_empty',
+ validate: {
+ validationType: ''
+ }
+ },
+ {
+ type: 'textfield',
+ key: 'field_undefined',
+ validate: {}
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/values-not-allowed.js b/packages/form-json-schema/test/fixtures/values-not-allowed.js
new file mode 100644
index 000000000..37d277941
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/values-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ values: []
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/values',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/8/then/properties/values/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/8/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/valuesExpression-not-allowed.js b/packages/form-json-schema/test/fixtures/valuesExpression-not-allowed.js
new file mode 100644
index 000000000..144234bf6
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/valuesExpression-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ valuesExpression: '=foo'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/valuesExpression',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/8/then/properties/valuesExpression/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/8/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/valuesKey-invalid.js b/packages/form-json-schema/test/fixtures/valuesKey-invalid.js
new file mode 100644
index 000000000..68e7b138f
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/valuesKey-invalid.js
@@ -0,0 +1,20 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'select',
+ key: 'select',
+ valuesKey: 'foo bar'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/valuesKey',
+ schemaPath: '#/properties/components/items/properties/valuesKey/pattern',
+ keyword: 'pattern',
+ params: { pattern: '^[^\\s]*$' },
+ message: 'must match pattern "^[^\\s]*$"'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/valuesKey-not-allowed.js b/packages/form-json-schema/test/fixtures/valuesKey-not-allowed.js
new file mode 100644
index 000000000..30b7f0e81
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/valuesKey-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ valuesKey: 'foo'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/valuesKey',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/8/then/properties/valuesKey/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/8/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/verticalAlignment-invalid.js b/packages/form-json-schema/test/fixtures/verticalAlignment-invalid.js
new file mode 100644
index 000000000..29e27bb6b
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/verticalAlignment-invalid.js
@@ -0,0 +1,19 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'dynamiclist',
+ verticalAlignment: 'top'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/verticalAlignment',
+ schemaPath: '#/properties/components/items/properties/verticalAlignment/enum',
+ keyword: 'enum',
+ params: { allowedValues: [ 'start', 'center', 'end' ] },
+ message: 'must be equal to one of the allowed values'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/verticalAlignment-not-allowed.js b/packages/form-json-schema/test/fixtures/verticalAlignment-not-allowed.js
new file mode 100644
index 000000000..5ff2049df
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/verticalAlignment-not-allowed.js
@@ -0,0 +1,27 @@
+export const form = {
+ type: 'default',
+ components: [
+ {
+ type: 'text',
+ text: 'text',
+ verticalAlignment: 'start'
+ }
+ ]
+};
+
+export const errors = [
+ {
+ instancePath: '/components/0/verticalAlignment',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/14/then/properties/verticalAlignment/false schema',
+ keyword: 'false schema',
+ params: {},
+ message: 'boolean schema is false'
+ },
+ {
+ instancePath: '/components/0',
+ schemaPath: '#/properties/components/items/allOf/1/allOf/14/if',
+ keyword: 'if',
+ params: { failingKeyword: 'then' },
+ message: 'must match "then" schema'
+ }
+];
\ No newline at end of file
diff --git a/packages/form-json-schema/test/fixtures/verticalAlignment.js b/packages/form-json-schema/test/fixtures/verticalAlignment.js
new file mode 100644
index 000000000..b240504d6
--- /dev/null
+++ b/packages/form-json-schema/test/fixtures/verticalAlignment.js
@@ -0,0 +1,62 @@
+export const form = {
+ 'id': 'id_default',
+ 'type': 'default',
+ 'components': [
+ {
+ 'id': 'id_group',
+ 'path': 'group',
+ 'label': 'Group',
+ 'type': 'group'
+ },
+ {
+ 'id': 'id_group_top',
+ 'path': 'group',
+ 'label': 'Group',
+ 'type': 'group',
+ 'verticalAlignment': 'start'
+ },
+ {
+ 'id': 'id_group_center',
+ 'path': 'group',
+ 'label': 'Group',
+ 'type': 'group',
+ 'verticalAlignment': 'center'
+ },
+ {
+ 'id': 'id_group_bottom',
+ 'path': 'group',
+ 'label': 'Group',
+ 'type': 'group',
+ 'verticalAlignment': 'end'
+ },
+ {
+ 'id': 'id_dynamiclist',
+ 'path': 'dynamiclist',
+ 'label': 'Dynamic List',
+ 'type': 'dynamiclist'
+ },
+ {
+ 'id': 'id_dynamiclist_top',
+ 'path': 'dynamiclist',
+ 'label': 'Dynamic List',
+ 'type': 'dynamiclist',
+ 'verticalAlignment': 'start'
+ },
+ {
+ 'id': 'id_dynamiclist_center',
+ 'path': 'dynamiclist',
+ 'label': 'Dynamic List',
+ 'type': 'dynamiclist',
+ 'verticalAlignment': 'center'
+ },
+ {
+ 'id': 'id_dynamiclist_bottom',
+ 'path': 'dynamiclist',
+ 'label': 'Dynamic List',
+ 'type': 'dynamiclist',
+ 'verticalAlignment': 'end'
+ }
+ ]
+};
+
+export const errors = null;
\ No newline at end of file
diff --git a/packages/form-json-schema/test/helpers/index.js b/packages/form-json-schema/test/helpers/index.js
new file mode 100644
index 000000000..1a3eb5c9e
--- /dev/null
+++ b/packages/form-json-schema/test/helpers/index.js
@@ -0,0 +1,55 @@
+const {
+ forEach,
+ set
+} = require('min-dash');
+
+const { default: Ajv } = require('ajv');
+const AjvErrors = require('ajv-errors');
+
+module.exports = {
+ createValidator,
+ withErrorMessages
+};
+
+function createValidator(schema, errors) {
+
+ const ajv = new Ajv({
+ allErrors: true,
+ strict: false
+ });
+
+ AjvErrors(ajv);
+
+ return ajv.compile(withErrorMessages(schema, errors));
+}
+
+function withErrorMessages(schema, errors) {
+
+ if (!errors || !errors.length) {
+ return schema;
+ }
+
+ // clone a new copy
+ let newSchema = JSON.parse(JSON.stringify(schema));
+
+ // set keyword for given path
+ forEach(errors, function(error) {
+ newSchema = setErrorMessage(newSchema, error);
+ });
+
+ return newSchema;
+}
+
+function setErrorMessage(schema, error) {
+ const {
+ path,
+ errorMessage
+ } = error;
+
+ const errorMessagePath = [
+ ...path,
+ 'errorMessage'
+ ];
+
+ return set(schema, errorMessagePath, errorMessage);
+}
\ No newline at end of file
diff --git a/packages/form-json-schema/test/spec/schema.spec.js b/packages/form-json-schema/test/spec/schema.spec.js
new file mode 100644
index 000000000..225f3587a
--- /dev/null
+++ b/packages/form-json-schema/test/spec/schema.spec.js
@@ -0,0 +1,21 @@
+const { default: Ajv } = require('ajv');
+const { expect } = require('chai');
+
+const schema = require('../../resources/schema.json');
+
+describe('schema validation', function() {
+
+ it('should be valid', function() {
+
+ // given
+ const ajv = new Ajv();
+
+ // when
+ const valid = ajv.validateSchema(schema);
+
+ // then
+ expect(valid).to.be.true;
+ expect(valid.errors).to.not.exist;
+ });
+
+});
\ No newline at end of file
diff --git a/packages/form-json-schema/test/spec/validation.spec.js b/packages/form-json-schema/test/spec/validation.spec.js
new file mode 100644
index 000000000..b2d935393
--- /dev/null
+++ b/packages/form-json-schema/test/spec/validation.spec.js
@@ -0,0 +1,287 @@
+const { expect } = require('chai');
+
+const util = require('util');
+
+const schema = require('../../resources/schema.json');
+
+const errorMessages = require('../../resources/error-messages.json');
+
+const {
+ createValidator
+} = require('../helpers');
+
+const validator = createValidator(schema, errorMessages);
+
+
+describe('validation', function() {
+
+ function validateForm(template) {
+
+ const valid = validator(template);
+
+ const errors = validator.errors;
+
+ return {
+ valid,
+ errors
+ };
+ }
+
+ function testForm(name, file, only = false) {
+
+ if (!file) {
+ file = `../fixtures/${name}.js`;
+ }
+
+ (only ? it.only : it)('should validate form - ' + name, async function() {
+
+ // given
+ const testDefinition = await import(file);
+
+ const {
+ errors: expectedErrors,
+ form
+ } = testDefinition;
+
+ // when
+ const {
+ errors
+ } = validateForm(form);
+
+ if (only) {
+ printNested(errors);
+ }
+
+ // then
+ expect(errors).to.eql(expectedErrors);
+ });
+ }
+
+ // eslint-disable-next-line no-unused-vars
+ function testOnly(name, file) {
+ return testForm(name, file, true);
+ }
+
+
+ testForm('simple');
+
+
+ testForm('complex');
+
+
+ testForm('groups');
+
+
+ testForm('schemaVersion-not-supported');
+
+
+ testForm('expression-properties');
+
+
+ testForm('increment');
+
+
+ testForm('no-action');
+
+
+ testForm('no-subtype');
+
+
+ testForm('no-values-property');
+
+
+ testForm('dynamiclists');
+
+
+ testForm('verticalAlignment');
+
+
+ testForm('verticalAlignment-invalid');
+
+
+ testForm('validate-validationType');
+
+
+ testForm('layout-empty-row');
+
+
+ describe('rules - required properties', function() {
+
+
+ testForm('no-key');
+
+ });
+
+
+ describe('rules - allowed properties', function() {
+
+ testForm('text-not-allowed');
+
+
+ testForm('label-not-allowed');
+
+
+ testForm('description-not-allowed');
+
+
+ testForm('key-not-allowed');
+
+
+ testForm('disabled-not-allowed');
+
+
+ testForm('action-not-allowed');
+
+
+ testForm('source-not-allowed');
+
+
+ testForm('alt-not-allowed');
+
+
+ testForm('subtype-not-allowed');
+
+
+ testForm('dateLabel-not-allowed');
+
+
+ testForm('disallowPassedDates-not-allowed');
+
+
+ testForm('timeLabel-not-allowed');
+
+
+ testForm('timeInterval-not-allowed');
+
+
+ testForm('use24h-not-allowed');
+
+
+ testForm('timeSerializingFormat-not-allowed');
+
+
+ testForm('increment-not-allowed');
+
+
+ testForm('decimalDigits-not-allowed');
+
+
+ testForm('serializeToString-not-allowed');
+
+
+ testForm('searchable-not-allowed');
+
+
+ testForm('validate-not-allowed');
+
+
+ testForm('values-not-allowed');
+
+
+ testForm('valuesKey-not-allowed');
+
+
+ testForm('valuesExpression-not-allowed');
+
+
+ testForm('validate-max-not-allowed');
+
+
+ testForm('validate-min-not-allowed');
+
+
+ testForm('validate-pattern-not-allowed');
+
+
+ testForm('validate-validationType-not-allowed');
+
+
+ testForm('validate-maxLength-not-allowed');
+
+
+ testForm('validate-minLength-not-allowed');
+
+
+ testForm('appearance-prefixAdorner-not-allowed');
+
+
+ testForm('appearance-suffixAdorner-not-allowed');
+
+
+ testForm('defaultValue-not-allowed');
+
+
+ testForm('height-not-allowed');
+
+
+ testForm('showOutline-not-allowed');
+
+
+ testForm('path-not-allowed');
+
+
+ testForm('readonly-not-allowed');
+
+
+ testForm('verticalAlignment-not-allowed');
+
+
+ testForm('components-not-allowed');
+
+ });
+
+
+ describe('rules - default', function() {
+
+ testForm('layout-not-allowed');
+
+
+ testForm('properties-not-allowed');
+
+
+ testForm('conditional-not-allowed');
+
+ });
+
+
+ describe('rules - defaultValue type', function() {
+
+ testForm('defaultValue-no-boolean');
+
+
+ testForm('defaultValue-no-string');
+
+
+ testForm('defaultValue-no-string-or-number');
+
+
+ testForm('defaultValue-no-array');
+
+ });
+
+
+ describe('format', function() {
+
+ testForm('key-invalid');
+
+
+ testForm('path-invalid');
+
+
+ testForm('valuesKey-invalid');
+
+ });
+
+});
+
+
+// helpers /////////////////
+
+// eslint-disable-next-line no-unused-vars
+function printNested(object) {
+ console.log(util.inspect(object, {
+ showHidden: false,
+ depth: null,
+ colors: true
+ }));
+}