From 0644cf4194dcbdbbb090c606e58ed9f11a4b579a Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Mon, 18 Nov 2024 18:27:42 -0800 Subject: [PATCH 1/8] feat: generate a json schema from zod defnied schema --- package-lock.json | 590 +++++++++++++++++++++++++++------- package.json | 9 +- tools/generate-json-schema.ts | 128 ++++++++ 3 files changed, 606 insertions(+), 121 deletions(-) create mode 100644 tools/generate-json-schema.ts diff --git a/package-lock.json b/package-lock.json index 835c075a..198e9854 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "@semantic-release/npm": "^12.0.1", "jsdom": "^25.0.1", "lefthook": "^1.7.18", - "npm-run-all": "^4.1.5", + "npm-run-all": "^2.1.0", "sass-embedded": "^1.80.1", "semantic-release": "^24.1.2", "svg-sprite": "^2.0.4", @@ -32,7 +32,9 @@ "vite-plugin-banner": "^0.8.0", "vite-plugin-compression": "^0.5.1", "vite-plugin-html": "^3.2.2", - "vite-plugin-static-copy": "^2.0.0" + "vite-plugin-static-copy": "^2.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.23.5" } }, "node_modules/@babel/code-frame": { @@ -3214,6 +3216,42 @@ "node": ">= 8" } }, + "node_modules/cross-spawn-async": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz", + "integrity": "sha512-snteb3aVrxYYOX9e8BabYFK9WhCDhTlw1YQktfTthBogxri4/2r9U2nQc0ffY73ZAxezDc+U8gvHAeU1wy1ubQ==", + "deprecated": "cross-spawn no longer requires a build toolchain, use it instead", + "dev": true, + "license": "MIT", + "dependencies": { + "lru-cache": "^4.0.0", + "which": "^1.2.8" + } + }, + "node_modules/cross-spawn-async/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/cross-spawn-async/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/crypto-random-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", @@ -3618,6 +3656,13 @@ "node": ">=12" } }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true, + "license": "MIT" + }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -4067,6 +4112,22 @@ "dev": true, "license": "MIT" }, + "node_modules/event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -4281,6 +4342,13 @@ "node": ">= 6" } }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true, + "license": "MIT" + }, "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -4628,6 +4696,29 @@ "uglify-js": "^3.1.4" } }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -5361,6 +5452,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true, + "license": "MIT" + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -6011,6 +6109,12 @@ "dev": true, "license": "ISC" }, + "node_modules/map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==", + "dev": true + }, "node_modules/marked": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", @@ -6053,15 +6157,6 @@ "dev": true, "license": "CC0-1.0" }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, "node_modules/meow": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", @@ -6245,13 +6340,6 @@ "dev": true, "license": "MIT" }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true, - "license": "MIT" - }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -6490,20 +6578,21 @@ } }, "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-2.1.0.tgz", + "integrity": "sha512-se5KsqO3nAYssWtZPd76J/CakbRHM1WXypNj7w5Nmi52QYi5LDN1eyt2OzLpv6s2fyF9nurHR9/NmpxWCm602A==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", + "chalk": "^1.1.3", + "cross-spawn-async": "^2.1.9", + "minimatch": "^3.0.0", + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.1", + "ps-tree": "^1.0.1", + "read-pkg": "^1.1.0", + "read-pkg-up": "^1.0.1", + "shell-quote": "^1.4.3", "string.prototype.padend": "^3.0.0" }, "bin": { @@ -6512,39 +6601,45 @@ "run-s": "bin/run-s/index.js" }, "engines": { - "node": ">= 4" + "node": ">= 0.10", + "npm": ">= 2" } }, - "node_modules/npm-run-all/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/npm-run-all/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, "engines": { - "node": ">=4" + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/npm-run-all/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "license": "MIT", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" }, "engines": { - "node": ">=4.8" + "node": ">=0.10.0" } }, "node_modules/npm-run-all/node_modules/escape-string-regexp": { @@ -6557,16 +6652,6 @@ "node": ">=0.8.0" } }, - "node_modules/npm-run-all/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/npm-run-all/node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -6574,6 +6659,23 @@ "dev": true, "license": "ISC" }, + "node_modules/npm-run-all/node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-all/node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -6587,42 +6689,57 @@ "validate-npm-package-license": "^3.0.1" } }, - "node_modules/npm-run-all/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "node_modules/npm-run-all/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", "dev": true, "license": "MIT", + "dependencies": { + "error-ex": "^1.2.0" + }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/npm-run-all/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", "dev": true, "license": "MIT", "dependencies": { - "pify": "^3.0.0" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, "node_modules/npm-run-all/node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "license": "MIT", "dependencies": { - "load-json-file": "^4.0.0", + "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "path-type": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/npm-run-all/node_modules/semver": { @@ -6635,53 +6752,40 @@ "semver": "bin/semver" } }, - "node_modules/npm-run-all/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/npm-run-all/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "license": "MIT", "dependencies": { - "shebang-regex": "^1.0.0" + "ansi-regex": "^2.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/npm-run-all/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/npm-run-all/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", "dev": true, "license": "MIT", + "dependencies": { + "is-utf8": "^0.2.0" + }, "engines": { "node": ">=0.10.0" } }, "node_modules/npm-run-all/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" + "node": ">=0.8.0" } }, "node_modules/npm-run-path": { @@ -10034,6 +10138,19 @@ "dev": true, "license": "MIT" }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "license": [ + "MIT", + "Apache2" + ], + "dependencies": { + "through": "~2.3" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -10053,19 +10170,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -10076,6 +10180,29 @@ "node": ">=4" } }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pkg-conf": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", @@ -10227,6 +10354,29 @@ "dev": true, "license": "ISC" }, + "node_modules/ps-tree": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", + "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-stream": "=3.3.4" + }, + "bin": { + "ps-tree": "bin/ps-tree.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true, + "license": "ISC" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -10319,6 +10469,160 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/read-pkg-up/node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg-up/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg-up/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read-pkg/node_modules/parse-json": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.1.0.tgz", @@ -11616,6 +11920,19 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -11644,6 +11961,16 @@ "node": "*" } }, + "node_modules/stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer": "~0.1.1" + } + }, "node_modules/stream-combiner2": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", @@ -13026,6 +13353,13 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true, + "license": "ISC" + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -13080,6 +13414,26 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.23.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.5.tgz", + "integrity": "sha512-5wlSS0bXfF/BrL4jPAbz9da5hDlDptdEppYfe+x4eIJ7jioqKG9uUxOwPzqof09u/XeVdrgFu29lZi+8XNDJtA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.23.3" + } } } } diff --git a/package.json b/package.json index ed2c06ce..faffccbc 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,8 @@ "travis-deploy-once": "travis-deploy-once --pro", "prepush": "npm test", "prepare": "lefthook install", - "postmerge": "lefthook install" + "postmerge": "lefthook install", + "generate:jsonSchema": "node --experimental-strip-types --no-warnings ./tools/generate-json-schema.ts" }, "devDependencies": { "@biomejs/biome": "^1.9.3", @@ -92,7 +93,7 @@ "@semantic-release/npm": "^12.0.1", "jsdom": "^25.0.1", "lefthook": "^1.7.18", - "npm-run-all": "^4.1.5", + "npm-run-all": "^2.1.0", "sass-embedded": "^1.80.1", "semantic-release": "^24.1.2", "svg-sprite": "^2.0.4", @@ -100,7 +101,9 @@ "vite-plugin-banner": "^0.8.0", "vite-plugin-compression": "^0.5.1", "vite-plugin-html": "^3.2.2", - "vite-plugin-static-copy": "^2.0.0" + "vite-plugin-static-copy": "^2.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.23.5" }, "dependencies": { "@draggable/formeo-languages": "^3.1.3", diff --git a/tools/generate-json-schema.ts b/tools/generate-json-schema.ts new file mode 100644 index 00000000..438bc181 --- /dev/null +++ b/tools/generate-json-schema.ts @@ -0,0 +1,128 @@ +import { join } from 'node:path' +import { writeFileSync } from 'node:fs' +import { z } from 'zod' +import { zodToJsonSchema } from 'zod-to-json-schema' + +const __dirname = join(new URL('.', import.meta.url).pathname) + +const htmlAttributesSchema = z.record( + z.string(), + z.union([ + z.string(), + z.number(), + z.boolean(), + z.function(), + z.record(z.string(), z.string()), // for style objects + ]), +) + +const formDataSchema = z + .object({ + id: z.string().uuid(), + stages: z.record( + z.string().uuid(), + z.object({ + id: z.string().uuid(), + children: z.array(z.string().uuid()), + }), + ), + rows: z.record( + z.string().uuid(), + z.object({ + id: z.string().uuid(), + children: z.array(z.string().uuid()), + className: z.union([z.string(), z.array(z.string())]).optional(), + config: z + .object({ + fieldset: z.boolean().optional(), + legend: z.string().optional(), + inputGroup: z.boolean().optional(), + }) + .optional(), + }), + ), + columns: z.record( + z.string().uuid(), + z.object({ + id: z.string().uuid(), + children: z.array(z.string().uuid()), + className: z.string().optional(), + config: z + .object({ + width: z.string().optional(), + }) + .optional(), + }), + ), + fields: z.record( + z.string().uuid(), + z.object({ + id: z.string().uuid(), + tag: z.string(), + attrs: htmlAttributesSchema.optional(), + config: z + .object({ + label: z.string().optional(), + }) + .optional(), + meta: z + .object({ + group: z.string().optional(), + icon: z.string().optional(), + id: z.string().optional(), + }) + .optional(), + conditions: z + .array( + z.object({ + if: z + .array( + z.object({ + source: z.string().optional(), + sourceProperty: z.string().optional(), + comparison: z.string().optional(), + target: z.string().optional(), + targetProperty: z.string().optional(), + }), + ) + .optional(), + // "then" is not a keyword when used as a key in + // an object and required for the schema + // biome-ignore lint/suspicious/noThenProperty: + then: z + .array( + z.object({ + target: z.string().optional(), + targetProperty: z.string().optional(), + assignment: z.string().optional(), + value: z.string().optional(), + }), + ) + .optional(), + }), + ) + .optional(), + }), + ), + }) + .describe('Schema definition for formData') + +const reorderSchema = (schema: object) => { + const topProperties = ['$schema', 'title', 'description'] + return { + ...topProperties.reduce( + (acc, key) => { + if (key in schema) { + acc[key] = schema[key as keyof typeof schema] + } + return acc + }, + {} as Record, + ), + ...schema, + } +} +const jsonSchema = zodToJsonSchema(formDataSchema, { name: 'formData', nameStrategy: 'title' }) +const orderedJsonSchema = reorderSchema(jsonSchema) +const distDir = join(__dirname, '../dist') +writeFileSync(join(distDir, 'formData.schema.json'), JSON.stringify(orderedJsonSchema, null, 2)) From b3410d70233c15ce978bbfb0fc8e83ef0899dd64 Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Mon, 18 Nov 2024 19:27:50 -0800 Subject: [PATCH 2/8] fix: add missing properties --- tools/generate-json-schema.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/generate-json-schema.ts b/tools/generate-json-schema.ts index 438bc181..f7170118 100644 --- a/tools/generate-json-schema.ts +++ b/tools/generate-json-schema.ts @@ -13,6 +13,13 @@ const htmlAttributesSchema = z.record( z.boolean(), z.function(), z.record(z.string(), z.string()), // for style objects + z.array( + z.object({ + label: z.string(), + value: z.string(), + selected: z.boolean(), + }), + ), // for configurable html elements like h1, h2 etc ]), ) @@ -46,7 +53,7 @@ const formDataSchema = z z.object({ id: z.string().uuid(), children: z.array(z.string().uuid()), - className: z.string().optional(), + className: z.union([z.string(), z.array(z.string())]).optional(), config: z .object({ width: z.string().optional(), @@ -63,7 +70,10 @@ const formDataSchema = z config: z .object({ label: z.string().optional(), + hideLabel: z.boolean().optional(), + editableContent: z.boolean().optional(), }) + .catchall(z.any()) .optional(), meta: z .object({ @@ -72,6 +82,8 @@ const formDataSchema = z id: z.string().optional(), }) .optional(), + content: z.string().optional(), + action: z.object({}).optional(), conditions: z .array( z.object({ From b1f8910df69d6dae3ad284c4281ba8e8c2c299f1 Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Mon, 18 Nov 2024 21:07:00 -0800 Subject: [PATCH 3/8] chore: update schema to work with all current fields --- src/lib/js/components/columns/column.js | 26 ++++++++++------ tools/generate-json-schema.ts | 40 +++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/lib/js/components/columns/column.js b/src/lib/js/components/columns/column.js index e602fcf7..081f37f1 100644 --- a/src/lib/js/components/columns/column.js +++ b/src/lib/js/components/columns/column.js @@ -41,7 +41,7 @@ export default class Column extends Component { constructor(columnData) { super('column', { ...DEFAULT_DATA(), ...columnData }) - const children = this.createChildWrap() + const childWrap = this.createChildWrap() this.dom = dom.create({ tag: 'li', @@ -55,11 +55,11 @@ export default class Column extends Component { this.getActionButtons(), DOM_CONFIGS.editWindow(), DOM_CONFIGS.resizeHandle(new ResizeColumn()), - children, + childWrap, ], }) - this.processConfig(this.dom) + this.processConfig() events.columnResized = new window.CustomEvent('columnResized', { detail: { @@ -68,7 +68,7 @@ export default class Column extends Component { }, }) - Sortable.create(children, { + Sortable.create(childWrap, { animation: 150, fallbackClass: 'field-moving', forceFallback: true, @@ -98,11 +98,10 @@ export default class Column extends Component { * Process column configuration data * @param {Object} column */ - processConfig(column) { + processConfig() { const columnWidth = h.get(this.data, 'config.width') if (columnWidth) { - column.dataset.colWidth = columnWidth - column.style.width = columnWidth + this.setDomWidth(columnWidth) } } @@ -113,13 +112,22 @@ export default class Column extends Component { } } + /** + * Sets the width data and style for the column + * @param {string} width - The width value to be set for the column + * @returns {void} + */ + setDomWidth = width => { + this.dom.dataset.colWidth = width + this.dom.style.width = width + } + /** * Sets a columns width * @param {String} width percent or pixel */ setWidth = width => { - this.dom.dataset.colWidth = width - this.dom.style.width = width + this.setDomWidth(width) return this.set('config.width', width) } } diff --git a/tools/generate-json-schema.ts b/tools/generate-json-schema.ts index f7170118..c63c2b68 100644 --- a/tools/generate-json-schema.ts +++ b/tools/generate-json-schema.ts @@ -17,7 +17,7 @@ const htmlAttributesSchema = z.record( z.object({ label: z.string(), value: z.string(), - selected: z.boolean(), + selected: z.boolean().optional(), }), ), // for configurable html elements like h1, h2 etc ]), @@ -84,6 +84,26 @@ const formDataSchema = z .optional(), content: z.string().optional(), action: z.object({}).optional(), + options: z + .array( + z.object({ + label: z.string(), + value: z.string().optional(), + selected: z.boolean().optional(), + checked: z.boolean().optional(), + type: z + .array( + z.object({ + type: z.string(), + label: z.string(), + // value: z.string().optional(), + selected: z.boolean().optional(), + }), + ) + .optional(), + }), + ) + .optional(), conditions: z .array( z.object({ @@ -134,7 +154,23 @@ const reorderSchema = (schema: object) => { ...schema, } } + +function deepRemoveKeys(obj, exclude) { + if (Array.isArray(obj)) { + return obj.map(i => deepRemoveKeys(i, exclude)) + } + if (typeof obj === 'object') { + return Object.fromEntries( + Object.entries(obj) + .filter(([k, v]) => !(k in exclude && (exclude[k] === undefined || exclude[k] === v))) + .map(([k, v]) => [k, deepRemoveKeys(v, exclude)]), + ) + } + return obj +} + const jsonSchema = zodToJsonSchema(formDataSchema, { name: 'formData', nameStrategy: 'title' }) const orderedJsonSchema = reorderSchema(jsonSchema) +const filteredJsonSchema = deepRemoveKeys(orderedJsonSchema, { additionalProperties: false }) const distDir = join(__dirname, '../dist') -writeFileSync(join(distDir, 'formData.schema.json'), JSON.stringify(orderedJsonSchema, null, 2)) +writeFileSync(join(distDir, 'formData.schema.json'), JSON.stringify(filteredJsonSchema, null, 2)) From 98a351a2330a285e8fb0e5d681bf642259424f0e Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Mon, 18 Nov 2024 21:13:05 -0800 Subject: [PATCH 4/8] chore: change formData schema filename --- tools/generate-json-schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/generate-json-schema.ts b/tools/generate-json-schema.ts index c63c2b68..305e4173 100644 --- a/tools/generate-json-schema.ts +++ b/tools/generate-json-schema.ts @@ -173,4 +173,4 @@ const jsonSchema = zodToJsonSchema(formDataSchema, { name: 'formData', nameStrat const orderedJsonSchema = reorderSchema(jsonSchema) const filteredJsonSchema = deepRemoveKeys(orderedJsonSchema, { additionalProperties: false }) const distDir = join(__dirname, '../dist') -writeFileSync(join(distDir, 'formData.schema.json'), JSON.stringify(filteredJsonSchema, null, 2)) +writeFileSync(join(distDir, 'formData_schema.json'), JSON.stringify(filteredJsonSchema, null, 2)) From 9f83741df70c31909c600c0a86cac1efd6d663ee Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Mon, 18 Nov 2024 21:30:23 -0800 Subject: [PATCH 5/8] feat: add to formData json new schema key added to json BREAKING CHANGE: adding a new key to formData could potentially break existing software that assumes only the old keys --- package.json | 1 + src/lib/js/components/index.js | 7 +++-- src/lib/js/constants.js | 2 +- tools/generate-json-schema.ts | 53 +++++++++++++--------------------- 4 files changed, 27 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index faffccbc..fa54dea8 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "build:lib": "vite build --config vite.config.lib.mjs", "build": "npm-run-all -p build:icons build:demo", "prebuild": "npm run build:lib", + "postbuild": "npm run generate:jsonSchema", "build:demo": "vite build --mode demo", "build:demo:watch": "vite build --mode demo --watch", "build:icons": "node ./tools/generate-sprite", diff --git a/src/lib/js/components/index.js b/src/lib/js/components/index.js index 988472b8..bc8e72bf 100644 --- a/src/lib/js/components/index.js +++ b/src/lib/js/components/index.js @@ -7,7 +7,7 @@ import RowsData from './rows/index.js' import ColumnsData from './columns/index.js' import FieldsData from './fields/index.js' import ExternalsData from './externals.js' -import { SESSION_FORMDATA_KEY } from '../constants.js' +import { SESSION_FORMDATA_KEY, version } from '../constants.js' export const Stages = StagesData export const Rows = RowsData @@ -78,7 +78,10 @@ export class Components extends Data { } get json() { - return window.JSON.stringify(this.formData) + return window.JSON.stringify({ + $schema: `https://cdn.jsdelivr.net/npm/formeo@${version}/dist/formData_schema.json`, + ...this.formData, + }) } get formData() { diff --git a/src/lib/js/constants.js b/src/lib/js/constants.js index ac187a80..d2ec07d6 100644 --- a/src/lib/js/constants.js +++ b/src/lib/js/constants.js @@ -3,7 +3,7 @@ import pkg from '../../../package.json' with { type: 'json' } const isProd = import.meta.env?.PROD const name = pkg.name -const version = pkg.version +export const version = pkg.version export const PACKAGE_NAME = name export const formeoSpriteId = 'formeo-sprite' diff --git a/tools/generate-json-schema.ts b/tools/generate-json-schema.ts index 305e4173..1ce67d7a 100644 --- a/tools/generate-json-schema.ts +++ b/tools/generate-json-schema.ts @@ -82,26 +82,28 @@ const formDataSchema = z id: z.string().optional(), }) .optional(), - content: z.string().optional(), + content: z.any().optional(), action: z.object({}).optional(), options: z .array( - z.object({ - label: z.string(), - value: z.string().optional(), - selected: z.boolean().optional(), - checked: z.boolean().optional(), - type: z - .array( - z.object({ - type: z.string(), - label: z.string(), - // value: z.string().optional(), - selected: z.boolean().optional(), - }), - ) - .optional(), - }), + z + .object({ + label: z.string(), + value: z.string().optional(), + selected: z.boolean().optional(), + checked: z.boolean().optional(), + type: z + .array( + z.object({ + type: z.string(), + label: z.string(), + // value: z.string().optional(), + selected: z.boolean().optional(), + }), + ) + .optional(), + }) + .catchall(z.any()), ) .optional(), conditions: z @@ -155,22 +157,7 @@ const reorderSchema = (schema: object) => { } } -function deepRemoveKeys(obj, exclude) { - if (Array.isArray(obj)) { - return obj.map(i => deepRemoveKeys(i, exclude)) - } - if (typeof obj === 'object') { - return Object.fromEntries( - Object.entries(obj) - .filter(([k, v]) => !(k in exclude && (exclude[k] === undefined || exclude[k] === v))) - .map(([k, v]) => [k, deepRemoveKeys(v, exclude)]), - ) - } - return obj -} - const jsonSchema = zodToJsonSchema(formDataSchema, { name: 'formData', nameStrategy: 'title' }) const orderedJsonSchema = reorderSchema(jsonSchema) -const filteredJsonSchema = deepRemoveKeys(orderedJsonSchema, { additionalProperties: false }) const distDir = join(__dirname, '../dist') -writeFileSync(join(distDir, 'formData_schema.json'), JSON.stringify(filteredJsonSchema, null, 2)) +writeFileSync(join(distDir, 'formData_schema.json'), JSON.stringify(orderedJsonSchema, null, 2)) From b3ba4e7d6bde8fc40d79f27b9dbd7df8ce044f6c Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Mon, 18 Nov 2024 21:44:45 -0800 Subject: [PATCH 6/8] chore: format json in demo --- src/demo/js/actionButtons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/demo/js/actionButtons.js b/src/demo/js/actionButtons.js index e94390d1..bb8102cd 100644 --- a/src/demo/js/actionButtons.js +++ b/src/demo/js/actionButtons.js @@ -7,7 +7,7 @@ const editorActions = (editor, renderer) => ({ renderFormWrap.style.display = 'block' renderer.render(editor.formData) }, - logJSON: () => console.log(editor.json), + logJSON: () => console.log(JSON.stringify(JSON.parse(editor.json), null, 2)), viewData: () => { for (const [key, val] of Object.entries(editor.formData)) { console.log(key, val) From 8e3a6314fe910804f36155b32a859685150c54c6 Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Tue, 19 Nov 2024 00:14:09 -0800 Subject: [PATCH 7/8] fix: remove unused conditions from formData reduce payload size --- src/lib/js/components/controls/form/button.js | 2 +- src/lib/js/components/fields/edit-panel.js | 4 +--- src/lib/js/components/fields/index.js | 20 +++++++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/lib/js/components/controls/form/button.js b/src/lib/js/components/controls/form/button.js index 9240dea1..f03b4e10 100644 --- a/src/lib/js/components/controls/form/button.js +++ b/src/lib/js/components/controls/form/button.js @@ -20,7 +20,7 @@ class ButtonControl extends Control { options: [ { label: i18n.get('button'), - type: ['button', 'submit', 'reset'].map((buttonType, index) => ({ + type: ['button', 'submit', 'reset'].map((buttonType) => ({ label: buttonType, type: buttonType, })), diff --git a/src/lib/js/components/fields/edit-panel.js b/src/lib/js/components/fields/edit-panel.js index 0c6a9bd4..0b5973aa 100644 --- a/src/lib/js/components/fields/edit-panel.js +++ b/src/lib/js/components/fields/edit-panel.js @@ -4,7 +4,6 @@ import actions from '../../common/actions.js' import EditPanelItem from './edit-panel-item.mjs' import { capitalize } from '../../common/helpers.mjs' import { slugify, toTitleCase } from '../../common/utils/string.mjs' -import { cleanObj } from '../../common/utils/object.mjs' /** * Element/Field class. @@ -176,8 +175,7 @@ export default class EditPanel { field: this.field, index: this.props.children.length, }) - - // debugger + this.editPanelItems.push(newOption) this.props.appendChild(newOption.dom) this.field.set(itemKey, itemData) diff --git a/src/lib/js/components/fields/index.js b/src/lib/js/components/fields/index.js index 03ba52f5..3e51039d 100644 --- a/src/lib/js/components/fields/index.js +++ b/src/lib/js/components/fields/index.js @@ -40,6 +40,26 @@ export class Fields extends ComponentData { } return found } + + getData = () => { + return Object.entries(this.data).reduce((acc, [key, val]) => { + const { conditions, ...data } = val?.getData() || val + + if (conditions?.length) { + let hasConditions = true + if (conditions.length === 1) { + const [firstCondition] = conditions + hasConditions = Boolean(firstCondition.if[0].source && firstCondition.then[0].target) + } + if (hasConditions) { + data.conditions = conditions + } + } + + acc[key] = data + return acc + }, {}) + } } const fields = new Fields() From e2d0ddaf3c7e487f1a9b847472f87ccbb041831d Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Tue, 19 Nov 2024 00:19:56 -0800 Subject: [PATCH 8/8] chore: add to the schema --- tools/generate-json-schema.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/generate-json-schema.ts b/tools/generate-json-schema.ts index 1ce67d7a..d7e92777 100644 --- a/tools/generate-json-schema.ts +++ b/tools/generate-json-schema.ts @@ -25,6 +25,7 @@ const htmlAttributesSchema = z.record( const formDataSchema = z .object({ + $schema: z.string().regex(/\.json$/), id: z.string().uuid(), stages: z.record( z.string().uuid(),