diff --git a/package-lock.json b/package-lock.json index 72bb3e9..894479c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,9 +19,9 @@ "@mat3ra/code": "2026.8.18-0", "@mat3ra/cove": "2026.8.19-4", "@mat3ra/esse": "2026.8.18-2", - "@mat3ra/ide": "https://github.com/mat3ra/ide/releases/download/wip-88b8881/ide.tgz", - "@mat3ra/made": "https://github.com/mat3ra/made/releases/download/wip-b5ab8c9/made.tgz", - "@mat3ra/mode": "https://github.com/mat3ra/mode/releases/download/wip-f8543e7/mode.tgz", + "@mat3ra/ide": "2026.8.18-0", + "@mat3ra/made": "2026.8.18-0", + "@mat3ra/mode": "2026.8.18-0", "@mat3ra/prode": "2026.8.18-0", "@mat3ra/standata": "2026.8.18-0", "@mat3ra/tsconfig": "^2024.6.3-0", @@ -3170,113 +3170,6 @@ "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", - "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "peer": 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/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, - "license": "MIT", - "peer": true - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/@exabyte-io/periodic-table.js": { "version": "2023.12.23-3", "resolved": "https://registry.npmjs.org/@exabyte-io/periodic-table.js/-/periodic-table.js-2023.12.23-3.tgz", @@ -3660,47 +3553,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause", - "peer": true - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -4486,9 +4338,9 @@ } }, "node_modules/@mat3ra/ide": { - "version": "0.0.0", - "resolved": "https://github.com/mat3ra/ide/releases/download/wip-88b8881/ide.tgz", - "integrity": "sha512-28neYHQrSoAqbjsrDmg9PsUi6D1L6PwYgI/tjehrzHmZwYxt6bQVpnIgO/S9lvKBbriwaUCkHJ1vFoXtAL1Umg==", + "version": "2026.8.18-0", + "resolved": "https://registry.npmjs.org/@mat3ra/ide/-/ide-2026.8.18-0.tgz", + "integrity": "sha512-xbV7KlxtFer+ailbZJwTbZttcjSLtIgw4BuQLFt+2VCAki67ojazbHqNAPCV1E0xxMQ+7X6NACOK8vA8ySjukw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4842,9 +4694,9 @@ } }, "node_modules/@mat3ra/made": { - "version": "0.0.0", - "resolved": "https://github.com/mat3ra/made/releases/download/wip-b5ab8c9/made.tgz", - "integrity": "sha512-UdhFBnX/4CZOIeMoCKh0H5O1JfTCAaxDrM11y4Mah8Cdql3fZErYJ9k8Jsfv7T4czBmlnZW9rLjhpm3jUTIgug==", + "version": "2026.8.18-0", + "resolved": "https://registry.npmjs.org/@mat3ra/made/-/made-2026.8.18-0.tgz", + "integrity": "sha512-00rb8HU7Kt8B9wARuJbhbfxFvK2KG0+aF8wJImMqV3jusUZ0qGp0sfQf3EYc68Z9VFMnSYMgiKROm9RajlfmfQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4882,9 +4734,9 @@ } }, "node_modules/@mat3ra/mode": { - "version": "0.0.0", - "resolved": "https://github.com/mat3ra/mode/releases/download/wip-f8543e7/mode.tgz", - "integrity": "sha512-uz8/4TRfa3eHBwZyi6Dre3BocTpr0bkLiUliKjFE3/k9YI3GKe/O675VSTGgQVFekcCxJMJuz/CsE+99rdD+LQ==", + "version": "2026.8.18-0", + "resolved": "https://registry.npmjs.org/@mat3ra/mode/-/mode-2026.8.18-0.tgz", + "integrity": "sha512-Q2nhBaS8tibFTivaOzQRh5Z3FbqkIIfYhTMKlnnM/sn+UJZPSal8KvUBaHEOUo8Enxe3NxB3oluX+u17vUo0yA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4896,7 +4748,7 @@ "@babel/preset-react": "7.16.7", "@babel/register": "^7.16.0", "@babel/runtime-corejs3": "7.16.8", - "@mat3ra/utils": "https://github.com/mat3ra/utils/releases/download/wip-8b2c388/utils.tgz", + "@mat3ra/utils": "2026.8.18-1", "@types/lodash": "^4.14.202", "@types/node": "^20.11.30", "@types/underscore": "^1.11.14", @@ -5195,10 +5047,116 @@ "node": ">=6.9.0" } }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils": { - "version": "0.0.0", - "resolved": "https://github.com/mat3ra/utils/releases/download/wip-8b2c388/utils.tgz", - "integrity": "sha512-vzShVrwuC16hi2HQiZsf7sGwnbu6+azHHsshd3OUVKnup+5vlZuIiFdUTXyK1jU5hoxiecCo2Wqb22UV8vlrzQ==", + "node_modules/@mat3ra/mode/node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@mat3ra/mode/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz", + "integrity": "sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.0", + "core-js-compat": "^3.18.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@mat3ra/mode/node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@mat3ra/mode/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mat3ra/prode": { + "version": "2026.8.18-0", + "resolved": "https://registry.npmjs.org/@mat3ra/prode/-/prode-2026.8.18-0.tgz", + "integrity": "sha512-BwsNYt++e/gIXrsawSlnSodoV304lZ8EybZGKeX9JQq/tWQEvz6SQDHpVMRsxEqS6aujIknKyh5YiVxAmo47Nw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/highcharts": "^5.0.44", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@mat3ra/code": "*", + "@mat3ra/esse": "*", + "@mat3ra/made": "*" + } + }, + "node_modules/@mat3ra/standata": { + "version": "2026.8.18-0", + "resolved": "https://registry.npmjs.org/@mat3ra/standata/-/standata-2026.8.18-0.tgz", + "integrity": "sha512-EltpDJnQnz9KcyvqdYHpwNCcpCciRAXWs6uKiCum1nstti1vHdbmTkkw7h0MWbdU2qa5SDX2I0aM0NSsPzfpTA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/nunjucks": "^3.2.6", + "@types/sprintf-js": "^1.1.4", + "cmd-ts": "^0.15.0", + "compare-versions": "^6.1.1", + "js-yaml": "^4.3.0", + "lodash": "^4.18.1", + "nunjucks": "^3.2.4", + "sprintf-js": "^1.1.3", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@mat3ra/esse": "*" + } + }, + "node_modules/@mat3ra/tsconfig": { + "version": "2024.6.3-0", + "resolved": "https://registry.npmjs.org/@mat3ra/tsconfig/-/tsconfig-2024.6.3-0.tgz", + "integrity": "sha512-dA3gKDSl9+vlZvot1DN+UXfZPgxPSyHkZrkfVCTOWvzwm/3NdJ4cTzrTxjBIWUrZukpVVtH5ao8FbXLB6RDQzQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@mat3ra/utils": { + "version": "2026.8.18-1", + "resolved": "https://registry.npmjs.org/@mat3ra/utils/-/utils-2026.8.18-1.tgz", + "integrity": "sha512-0J9s42sL/2S9tuwjUbxwo6/ORlGCbCvEqYSmHZgSmHNfzIc2mwuiXRNF0S5Al9EJDfYy6VO4WabDCrfpvCci8A==", "dev": true, "license": "ISC", "dependencies": { @@ -5226,975 +5184,41 @@ "node": ">=20.0.0" } }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/cli": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.29.7.tgz", - "integrity": "sha512-/75HwRbAYPqXv/Ax1h7Fg3IZfXgdU98jnA8H93/m/QBaPV3Hp5ICoLqzGYye1yHBCgpmXvtqgSUN8oOKX5tojQ==", + "node_modules/@mat3ra/utils/node_modules/mathjs": { + "version": "12.4.3", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.4.3.tgz", + "integrity": "sha512-oHdGPDbp7gO873xxG90RLq36IuicuKvbpr/bBG5g9c8Obm/VsKVrK9uoRZZHUodohzlnmCEqfDzbR3LH6m+aAQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.28", - "commander": "^6.2.0", - "convert-source-map": "^2.0.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.2.0", - "make-dir": "^2.1.0", - "slash": "^2.0.0" + "@babel/runtime": "^7.24.4", + "complex.js": "^2.1.1", + "decimal.js": "^10.4.3", + "escape-latex": "^1.2.0", + "fraction.js": "4.3.4", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^4.1.1" }, "bin": { - "babel": "bin/babel.js", - "babel-external-helpers": "bin/babel-external-helpers.js" + "mathjs": "bin/cli.js" }, "engines": { - "node": ">=6.9.0" - }, - "optionalDependencies": { - "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", - "chokidar": "^3.6.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">= 18" } }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "node_modules/@mat3ra/utils/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/eslint-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.29.7.tgz", - "integrity": "sha512-zxt+UJTOMKvUt3yOg+D58MLuz334pHp93qifMFcjIIO+9hN6t+ufw2gi7vDPMpxvfnHRR+3VVXvIjineCcgyXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.11.0", - "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/eslint-parser/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", - "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "debug": "^4.4.3", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.11" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/preset-env": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", - "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", - "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.29.7", - "@babel/plugin-syntax-import-attributes": "^7.29.7", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.29.7", - "@babel/plugin-transform-async-generator-functions": "^7.29.7", - "@babel/plugin-transform-async-to-generator": "^7.29.7", - "@babel/plugin-transform-block-scoped-functions": "^7.29.7", - "@babel/plugin-transform-block-scoping": "^7.29.7", - "@babel/plugin-transform-class-properties": "^7.29.7", - "@babel/plugin-transform-class-static-block": "^7.29.7", - "@babel/plugin-transform-classes": "^7.29.7", - "@babel/plugin-transform-computed-properties": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7", - "@babel/plugin-transform-dotall-regex": "^7.29.7", - "@babel/plugin-transform-duplicate-keys": "^7.29.7", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", - "@babel/plugin-transform-dynamic-import": "^7.29.7", - "@babel/plugin-transform-explicit-resource-management": "^7.29.7", - "@babel/plugin-transform-exponentiation-operator": "^7.29.7", - "@babel/plugin-transform-export-namespace-from": "^7.29.7", - "@babel/plugin-transform-for-of": "^7.29.7", - "@babel/plugin-transform-function-name": "^7.29.7", - "@babel/plugin-transform-json-strings": "^7.29.7", - "@babel/plugin-transform-literals": "^7.29.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", - "@babel/plugin-transform-member-expression-literals": "^7.29.7", - "@babel/plugin-transform-modules-amd": "^7.29.7", - "@babel/plugin-transform-modules-commonjs": "^7.29.7", - "@babel/plugin-transform-modules-systemjs": "^7.29.7", - "@babel/plugin-transform-modules-umd": "^7.29.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", - "@babel/plugin-transform-new-target": "^7.29.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", - "@babel/plugin-transform-numeric-separator": "^7.29.7", - "@babel/plugin-transform-object-rest-spread": "^7.29.7", - "@babel/plugin-transform-object-super": "^7.29.7", - "@babel/plugin-transform-optional-catch-binding": "^7.29.7", - "@babel/plugin-transform-optional-chaining": "^7.29.7", - "@babel/plugin-transform-parameters": "^7.29.7", - "@babel/plugin-transform-private-methods": "^7.29.7", - "@babel/plugin-transform-private-property-in-object": "^7.29.7", - "@babel/plugin-transform-property-literals": "^7.29.7", - "@babel/plugin-transform-regenerator": "^7.29.7", - "@babel/plugin-transform-regexp-modifiers": "^7.29.7", - "@babel/plugin-transform-reserved-words": "^7.29.7", - "@babel/plugin-transform-shorthand-properties": "^7.29.7", - "@babel/plugin-transform-spread": "^7.29.7", - "@babel/plugin-transform-sticky-regex": "^7.29.7", - "@babel/plugin-transform-template-literals": "^7.29.7", - "@babel/plugin-transform-typeof-symbol": "^7.29.7", - "@babel/plugin-transform-unicode-escapes": "^7.29.7", - "@babel/plugin-transform-unicode-property-regex": "^7.29.7", - "@babel/plugin-transform-unicode-regex": "^7.29.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.15", - "babel-plugin-polyfill-corejs3": "^0.14.0", - "babel-plugin-polyfill-regenerator": "^0.6.6", - "core-js-compat": "^3.48.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/preset-react": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.29.7.tgz", - "integrity": "sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "@babel/plugin-transform-react-display-name": "^7.29.7", - "@babel/plugin-transform-react-jsx": "^7.29.7", - "@babel/plugin-transform-react-jsx-development": "^7.29.7", - "@babel/plugin-transform-react-pure-annotations": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/@babel/runtime-corejs3": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.7.tgz", - "integrity": "sha512-ppj9ouYku+RX0ljtgZd+KMO5mkM2bCqg8H2PYAFWnLsHEIKIdRojqbJ2i3eVHrisuxy7nOFCmngTDdWtUCdXUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-js-pure": "^3.48.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", - "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.8", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", - "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8", - "core-js-compat": "^3.48.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", - "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mat3ra/mode/node_modules/@mat3ra/utils/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/@mat3ra/mode/node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/mode/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz", - "integrity": "sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.0", - "core-js-compat": "^3.18.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/mode/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/mode/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@mat3ra/mode/node_modules/mathjs": { - "version": "12.4.3", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-12.4.3.tgz", - "integrity": "sha512-oHdGPDbp7gO873xxG90RLq36IuicuKvbpr/bBG5g9c8Obm/VsKVrK9uoRZZHUodohzlnmCEqfDzbR3LH6m+aAQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime": "^7.24.4", - "complex.js": "^2.1.1", - "decimal.js": "^10.4.3", - "escape-latex": "^1.2.0", - "fraction.js": "4.3.4", - "javascript-natural-sort": "^0.7.1", - "seedrandom": "^3.0.5", - "tiny-emitter": "^2.1.0", - "typed-function": "^4.1.1" - }, - "bin": { - "mathjs": "bin/cli.js" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@mat3ra/prode": { - "version": "2026.8.18-0", - "resolved": "https://registry.npmjs.org/@mat3ra/prode/-/prode-2026.8.18-0.tgz", - "integrity": "sha512-BwsNYt++e/gIXrsawSlnSodoV304lZ8EybZGKeX9JQq/tWQEvz6SQDHpVMRsxEqS6aujIknKyh5YiVxAmo47Nw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/highcharts": "^5.0.44", - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "@mat3ra/code": "*", - "@mat3ra/esse": "*", - "@mat3ra/made": "*" - } - }, - "node_modules/@mat3ra/standata": { - "version": "2026.8.18-0", - "resolved": "https://registry.npmjs.org/@mat3ra/standata/-/standata-2026.8.18-0.tgz", - "integrity": "sha512-EltpDJnQnz9KcyvqdYHpwNCcpCciRAXWs6uKiCum1nstti1vHdbmTkkw7h0MWbdU2qa5SDX2I0aM0NSsPzfpTA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/nunjucks": "^3.2.6", - "@types/sprintf-js": "^1.1.4", - "cmd-ts": "^0.15.0", - "compare-versions": "^6.1.1", - "js-yaml": "^4.3.0", - "lodash": "^4.18.1", - "nunjucks": "^3.2.4", - "sprintf-js": "^1.1.3", - "ts-node": "^10.9.2", - "typescript": "^5.9.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@mat3ra/esse": "*" - } - }, - "node_modules/@mat3ra/tsconfig": { - "version": "2024.6.3-0", - "resolved": "https://registry.npmjs.org/@mat3ra/tsconfig/-/tsconfig-2024.6.3-0.tgz", - "integrity": "sha512-dA3gKDSl9+vlZvot1DN+UXfZPgxPSyHkZrkfVCTOWvzwm/3NdJ4cTzrTxjBIWUrZukpVVtH5ao8FbXLB6RDQzQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@mat3ra/utils": { - "version": "2026.4.15-1", - "resolved": "https://registry.npmjs.org/@mat3ra/utils/-/utils-2026.4.15-1.tgz", - "integrity": "sha512-ahIUAc9QzbZ+G3rvIPW5BqAwa4pPMjDwH4k3+1SrXSYUhM67z+S4FTpcsfNn4WkAgmJ2Az9l026RvP3xZcXF9g==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@babel/cli": "7.16.0", - "@babel/core": "7.24.1", - "@babel/eslint-parser": "7.16.3", - "@babel/plugin-proposal-class-properties": "7.16.0", - "@babel/preset-env": "7.16.4", - "@babel/preset-react": "7.16.7", - "@babel/preset-typescript": "^7.22.5", - "@babel/register": "^7.16.0", - "@babel/runtime-corejs3": "7.16.8", - "crypto-js": "^4.1.1", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "mathjs": "12.4.1", - "semver": "^7.5.3", - "ts-node": "^10.9.1", - "typescript": "^4.5.5", - "underscore": "^1.13.3", - "underscore.string": "^3.3.4", - "uuid": "8.3.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/cli": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.16.0.tgz", - "integrity": "sha512-WLrM42vKX/4atIoQB+eb0ovUof53UUvecb4qGjU2PDDWRiZr50ZpiV8NpcLo7iSxeGYrRG0Mqembsa+UrTAV6Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "commander": "^4.0.1", - "convert-source-map": "^1.1.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", - "make-dir": "^2.1.0", - "slash": "^2.0.0", - "source-map": "^0.5.0" - }, - "bin": { - "babel": "bin/babel.js", - "babel-external-helpers": "bin/babel-external-helpers.js" - }, - "engines": { - "node": ">=6.9.0" - }, - "optionalDependencies": { - "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", - "chokidar": "^3.4.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/core": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.1.tgz", - "integrity": "sha512-F82udohVyIgGAY2VVj/g34TpFUG606rumIHjTfVbssPg2zTR7PuuEpZcX8JA6sgBfIYmJrFtWgPvHQuJamVqZQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.1", - "@babel/parser": "^7.24.1", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@mat3ra/utils/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/eslint-parser": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.16.3.tgz", - "integrity": "sha512-iB4ElZT0jAt7PKVaeVulOECdGe6UnmA/O0P9jlF5g5GBOwDVbna8AXhHRu4s27xQf6OkveyA8iTDv1jHdDejgQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "eslint-scope": "^5.1.1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/eslint-parser/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz", - "integrity": "sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", - "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/preset-env": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.4.tgz", - "integrity": "sha512-v0QtNd81v/xKj4gNKeuAerQ/azeNn/G1B1qMLeXOcV8+4TWlD2j3NV1u8q29SDFBXx/NBq5kyEAO+0mpRgacjA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.3", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.2", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-async-generator-functions": "^7.16.4", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-class-static-block": "^7.16.0", - "@babel/plugin-proposal-dynamic-import": "^7.16.0", - "@babel/plugin-proposal-export-namespace-from": "^7.16.0", - "@babel/plugin-proposal-json-strings": "^7.16.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-object-rest-spread": "^7.16.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-proposal-private-property-in-object": "^7.16.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.0", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.0", - "@babel/plugin-transform-async-to-generator": "^7.16.0", - "@babel/plugin-transform-block-scoped-functions": "^7.16.0", - "@babel/plugin-transform-block-scoping": "^7.16.0", - "@babel/plugin-transform-classes": "^7.16.0", - "@babel/plugin-transform-computed-properties": "^7.16.0", - "@babel/plugin-transform-destructuring": "^7.16.0", - "@babel/plugin-transform-dotall-regex": "^7.16.0", - "@babel/plugin-transform-duplicate-keys": "^7.16.0", - "@babel/plugin-transform-exponentiation-operator": "^7.16.0", - "@babel/plugin-transform-for-of": "^7.16.0", - "@babel/plugin-transform-function-name": "^7.16.0", - "@babel/plugin-transform-literals": "^7.16.0", - "@babel/plugin-transform-member-expression-literals": "^7.16.0", - "@babel/plugin-transform-modules-amd": "^7.16.0", - "@babel/plugin-transform-modules-commonjs": "^7.16.0", - "@babel/plugin-transform-modules-systemjs": "^7.16.0", - "@babel/plugin-transform-modules-umd": "^7.16.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.0", - "@babel/plugin-transform-new-target": "^7.16.0", - "@babel/plugin-transform-object-super": "^7.16.0", - "@babel/plugin-transform-parameters": "^7.16.3", - "@babel/plugin-transform-property-literals": "^7.16.0", - "@babel/plugin-transform-regenerator": "^7.16.0", - "@babel/plugin-transform-reserved-words": "^7.16.0", - "@babel/plugin-transform-shorthand-properties": "^7.16.0", - "@babel/plugin-transform-spread": "^7.16.0", - "@babel/plugin-transform-sticky-regex": "^7.16.0", - "@babel/plugin-transform-template-literals": "^7.16.0", - "@babel/plugin-transform-typeof-symbol": "^7.16.0", - "@babel/plugin-transform-unicode-escapes": "^7.16.0", - "@babel/plugin-transform-unicode-regex": "^7.16.0", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.0", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.4.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.19.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/preset-modules": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", - "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/@babel/runtime-corejs3": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.8.tgz", - "integrity": "sha512-3fKhuICS1lMz0plI5ktOE/yEtBRMVxplzRkdn6mJQ197XiY0JnrzYV0+Mxozq3JZ8SBV9Ecurmw1XsGbwOf+Sg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "core-js-pure": "^3.20.2", - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@mat3ra/utils/node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mat3ra/utils/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz", - "integrity": "sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.0", - "core-js-compat": "^3.18.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@mat3ra/utils/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@mat3ra/utils/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "node": ">=10" } }, "node_modules/@mat3ra/utils/node_modules/typescript": { @@ -6203,7 +5227,6 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7016,47 +6039,6 @@ "eslint-scope": "5.1.1" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -7979,14 +6961,6 @@ "react-dom": ">=17.0.0" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", - "dev": true, - "license": "ISC", - "peer": true - }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -8024,19 +6998,8 @@ "bin": { "acorn": "bin/acorn" }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "engines": { + "node": ">=0.4.0" } }, "node_modules/acorn-walk": { @@ -8127,23 +7090,6 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -8959,28 +7905,6 @@ "@codemirror/view": "^6.0.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -9200,22 +8124,6 @@ "node-fetch": "^2.7.0" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/crypt": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", @@ -9387,14 +8295,6 @@ "node": ">=6" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -9478,20 +8378,6 @@ "dev": true, "license": "MIT" }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -9808,64 +8694,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -9890,270 +8718,6 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "peer": 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-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "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, - "license": "MIT", - "peer": true - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -10232,22 +8796,6 @@ "dev": true, "license": "MIT" }, - "node_modules/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, - "license": "MIT", - "peer": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/fast-uri": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", @@ -10265,17 +8813,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/fbemitter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", @@ -10321,24 +8858,10 @@ "peerDependencies": { "picomatch": "^3 || ^4" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, "node_modules/fill-range": { @@ -10390,30 +8913,6 @@ "node": ">=6" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", - "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", - "dev": true, - "license": "ISC", - "peer": true - }, "node_modules/flux": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", @@ -10668,23 +9167,6 @@ "node": ">= 6" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globalthis": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", @@ -10725,14 +9207,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -10746,17 +9220,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -10938,17 +9401,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -10973,17 +9425,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.8.19" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -11387,17 +9828,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -11576,14 +10006,6 @@ "dev": true, "license": "MIT" }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC", - "peer": true - }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", @@ -11654,14 +10076,6 @@ "node": ">=6" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -11762,14 +10176,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -11938,17 +10344,6 @@ "node": ">= 12" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -11959,21 +10354,6 @@ "node": ">=0.10.0" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -12040,14 +10420,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -12313,14 +10685,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -12655,25 +11019,6 @@ "wrappy": "1" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/orderedmap": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", @@ -12849,17 +11194,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -13025,17 +11359,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/prettier": { "version": "3.9.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.4.tgz", @@ -13261,28 +11584,6 @@ "node": ">=0.4.x" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true - }, "node_modules/raf-schd": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", @@ -13719,36 +12020,6 @@ "node": ">=4" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ripemd160": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", @@ -13852,31 +12123,6 @@ "dev": true, "license": "MIT" }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/safe-array-concat": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", @@ -14099,31 +12345,6 @@ "node": ">=8" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/side-channel": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", @@ -14412,20 +12633,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/style-mod": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", @@ -14440,20 +12647,6 @@ "dev": true, "license": "MIT" }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -14467,14 +12660,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/timers-browserify": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", @@ -14678,20 +12863,6 @@ "dev": true, "license": "MIT" }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/type-detect": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", @@ -14702,20 +12873,6 @@ "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -14990,28 +13147,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/url": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", @@ -15775,23 +13910,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/which-boxed-primitive": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", @@ -15888,17 +14006,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -15923,24 +14030,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 0946859..9006c20 100644 --- a/package.json +++ b/package.json @@ -49,9 +49,9 @@ "@mat3ra/ade": "2026.8.18-0", "@mat3ra/code": "2026.8.18-0", "@mat3ra/esse": "2026.8.18-2", - "@mat3ra/ide": "https://github.com/mat3ra/ide/releases/download/wip-88b8881/ide.tgz", - "@mat3ra/made": "https://github.com/mat3ra/made/releases/download/wip-b5ab8c9/made.tgz", - "@mat3ra/mode": "https://github.com/mat3ra/mode/releases/download/wip-f8543e7/mode.tgz", + "@mat3ra/ide": "2026.8.18-0", + "@mat3ra/made": "2026.8.18-0", + "@mat3ra/mode": "2026.8.18-0", "@mat3ra/prode": "2026.8.18-0", "@mat3ra/standata": "2026.8.18-0", "@mat3ra/tsconfig": "^2024.6.3-0", diff --git a/src/components/ExecutionUnit.tsx b/src/components/ExecutionUnit.tsx index 9792ace..2781b1a 100644 --- a/src/components/ExecutionUnit.tsx +++ b/src/components/ExecutionUnit.tsx @@ -13,13 +13,14 @@ import List from "@mui/material/List"; import ListItem from "@mui/material/ListItem"; import Radio from "@mui/material/Radio"; import Stack from "@mui/material/Stack"; -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Application } from "./Application"; import { type ExecutionUnitInput, ExecutionUnitInputFilePanel, } from "./ExecutionUnitInputFilePanel"; +import { TemplateVariablesPanel } from "./TemplateVariablesPanel"; import { DrawerContainer, DrawerContent, @@ -30,6 +31,7 @@ import { } from "./SideDrawer"; import TabsMenu from "@mat3ra/cove/dist/mui/components/tabs/TabsMenu"; +import { findUnresolvedVariables } from "../utils/templateVariables"; import type { ExecutableSchema, FlavorSchema } from "@mat3ra/esse/dist/js/types"; @@ -51,6 +53,8 @@ export type ExecutionUnitProps = { availableUnits: AnySubworkflowUnit[]; onChange: (value: string) => void; }>; + /** Labels for top-level rendering-context keys, when the host knows better than the default. */ + variableOriginOverrides?: Record; /** Injected component for unit details (results, monitors, post-processors). */ UnitDetailsComponent?: React.ComponentType<{ unit: ExecutionUnitSchema; @@ -81,6 +85,7 @@ export function ExecutionUnit({ units = [], UnitPointerFieldComponent, UnitDetailsComponent, + variableOriginOverrides, }: ExecutionUnitProps) { const [drawerContent, setDrawerContent] = useState<"context" | "materialList">("context"); const [isDrawerVisible, setIsDrawerVisible] = useState(false); @@ -264,6 +269,19 @@ export function ExecutionUnit({ [unit, onUpdate], ); + /** + * nunjucks substitutes an unknown variable with the empty string, so a typo does not fail — + * it quietly drops a value out of the input file. Checked per input so the warning can sit + * with the template it belongs to. + */ + const issuesByInput = useMemo( + () => + unit.input.map((inputRow: ExecutionUnitInput) => + findUnresolvedVariables(inputRow.template?.content, renderingContext), + ), + [unit.input, renderingContext], + ); + const tabs = unit.input.map((inputRow: ExecutionUnitInput, index: number) => { const label = inputRow.template.name; return { @@ -283,17 +301,6 @@ export function ExecutionUnit({ return ( - - {UnitPointerFieldComponent && unitPointerKeys.map((key) => ( - handleUnitKeyUpdate(key, value)} - /> - ))} - ))} @@ -360,36 +368,32 @@ export function ExecutionUnit({ setIsDrawerVisible((v) => !v)} icon={isDrawerVisible ? "shapes.arrow.right" : "shapes.arrow.left"} /> setDrawerContent("context")} icon="pages.context" /> setDrawerContent("materialList")} icon="entities.material" /> + title={drawerContent === "context" ? "Variables" : "Material"}> {drawerContent === "context" && ( -
-                                    {JSON.stringify(renderingContext ?? {}, null, "    ")}
-                                
+ )} {drawerContent === "materialList" && ( @@ -424,6 +428,30 @@ export function ExecutionUnit({
+ {/* + Execution order is a wiring detail, not what someone opens a unit to change: it + used to sit above everything, so the first thing the input editor showed was a + pointer to another unit. It keeps its place in the form, at the end and collapsed. + */} + {UnitPointerFieldComponent && ( + + + {unitPointerKeys.map((key) => ( + handleUnitKeyUpdate(key, value)} + /> + ))} + + + )}
); } diff --git a/src/components/ExecutionUnitInputFilePanel.tsx b/src/components/ExecutionUnitInputFilePanel.tsx index f62b703..9afa35a 100644 --- a/src/components/ExecutionUnitInputFilePanel.tsx +++ b/src/components/ExecutionUnitInputFilePanel.tsx @@ -1,4 +1,5 @@ import CodeMirror from "@mat3ra/cove/dist/other/codemirror"; +import Alert from "@mui/material/Alert"; import { getProgrammingLanguageFromFileExtension } from "@mat3ra/code/dist/js/utils"; import type { ExecutionUnitInputItemSchema } from "@mat3ra/esse/dist/js/types"; import Stack from "@mui/material/Stack"; @@ -6,6 +7,7 @@ import React from "react"; import TabsMenu from "@mat3ra/cove/dist/mui/components/tabs/TabsMenu"; import type { TabItem } from "@mat3ra/cove/dist/mui/components/tabs/types"; +import type { TemplateIssue } from "../utils/templateVariables"; /** `input[]` row for an execution unit; optional `name` is set by `setInputItemNameByIndex` for tab labels. */ export type ExecutionUnitInput = ExecutionUnitInputItemSchema & { @@ -26,6 +28,8 @@ type ExecutionUnitInputFilePanelProps = { lineWrapping: boolean; adjustable?: boolean; isStandalone?: boolean; + /** Variables in this template that will render to nothing. */ + issues?: TemplateIssue[]; }; const codeMirrorDefaults: Record = { @@ -50,6 +54,7 @@ export function ExecutionUnitInputFilePanel({ lineWrapping, adjustable, isStandalone, + issues = [], }: ExecutionUnitInputFilePanelProps) { const contentTabIdString = `template-${index}`; const previewTabIdString = `preview-${index}`; @@ -84,6 +89,23 @@ export function ExecutionUnitInputFilePanel({ id={String(index)} className={`ExecutionFile ${isActive ? "active" : ""}`}> + {/* + Named here rather than left to the preview: nunjucks renders an unknown variable + as the empty string, so the preview of a typo looks like a value that is simply + blank. + */} + {issues.length > 0 && ( + + {issues + .map( + (issue) => + `line ${issue.line}: ${issue.name}${ + issue.suggestion ? ` — did you mean ${issue.suggestion}?` : "" + }`, + ) + .join(" · ")} + + )} ; + /** Host-supplied labels for top-level context keys; see `describeOrigin`. */ + originOverrides?: Record; +} + +/** "renders with: Si … · espresso", from the context itself rather than a separate prop. */ +function describeRenderTarget(context?: Record): string { + const read = (key: string) => { + const value = (context?.[key] ?? {}) as { name?: unknown }; + return typeof value?.name === "string" ? value.name : undefined; + }; + return [read("material"), read("application")].filter(Boolean).join(" · "); +} + +function groupByOrigin(variables: ContextVariable[]): [string, ContextVariable[]][] { + const groups = new Map(); + variables.forEach((variable) => { + const bucket = groups.get(variable.origin); + if (bucket) bucket.push(variable); + else groups.set(variable.origin, [variable]); + }); + return [...groups.entries()]; +} + +/** + * What a template can write, and where each value came from. + * + * Replaces a `
` of the whole rendering context as JSON — everything available, in the shape
+ * it happened to be stored in, with no indication of which parts came from the Settings tab and
+ * which arrive at job runtime. Clicking a row copies the `{{ … }}` expression: inserting at the
+ * cursor needs the editor's `EditorView`, which cove's CodeMirror wrapper does not expose.
+ *
+ * Unresolved variables are reported by {@link ExecutionUnitInputFilePanel}, directly above the
+ * template they are in, rather than here as well.
+ */
+export function TemplateVariablesPanel({
+    renderingContext,
+    originOverrides,
+}: TemplateVariablesPanelProps) {
+    const [search, setSearch] = useState("");
+    const [copied, setCopied] = useState(null);
+
+    const variables = useMemo(
+        () => flattenRenderingContext(renderingContext, { originOverrides }),
+        [renderingContext, originOverrides],
+    );
+
+    const needle = search.trim().toLowerCase();
+    const visible = needle
+        ? variables.filter(
+              (variable) =>
+                  variable.path.toLowerCase().includes(needle) ||
+                  variable.preview.toLowerCase().includes(needle),
+          )
+        : variables;
+
+    const copy = (path: string) => {
+        const expression = `{{ ${path} }}`;
+        navigator.clipboard?.writeText(expression).catch(() => undefined);
+        setCopied(path);
+        // Fire-and-forget; the panel only needs the label to settle back.
+        setTimeout(() => setCopied((current) => (current === path ? null : current)), 1200);
+    };
+
+    const renderTarget = describeRenderTarget(renderingContext);
+
+    return (
+        
+            {renderTarget ? (
+                
+                    renders with: {renderTarget}
+                
+            ) : null}
+
+             setSearch(event.target.value)}
+                placeholder="Search variables"
+                InputProps={{
+                    startAdornment: ,
+                    inputProps: { "data-tid": "template-variables-search" },
+                }}
+            />
+
+            {visible.length === 0 ? (
+                
+                    {variables.length === 0
+                        ? "No context to render this template with yet."
+                        : `Nothing matches “${search}”.`}
+                
+            ) : (
+                groupByOrigin(visible).map(([origin, rows]) => (
+                    
+                        
+                            {origin}
+                        
+                        {rows.map((variable) => (
+                            
+                                 copy(variable.path)}
+                                    data-tid={`template-variable-${variable.path}`}
+                                    sx={{
+                                        display: "flex",
+                                        gap: 1,
+                                        alignItems: "baseline",
+                                        px: 0.75,
+                                        py: 0.25,
+                                        borderRadius: 0.5,
+                                        cursor: "pointer",
+                                        "&:hover": { backgroundColor: "action.hover" },
+                                    }}
+                                >
+                                    
+                                        {variable.path}
+                                    
+                                    
+                                        {variable.preview}
+                                    
+                                
+                            
+                        ))}
+                    
+                ))
+            )}
+        
+    );
+}
+
+export default TemplateVariablesPanel;
diff --git a/src/utils/templateVariables.ts b/src/utils/templateVariables.ts
new file mode 100644
index 0000000..3d9f48b
--- /dev/null
+++ b/src/utils/templateVariables.ts
@@ -0,0 +1,382 @@
+/**
+ * Reading an input template against the context it will render with.
+ *
+ * Two questions the editor could not answer before: what is available to write into a template,
+ * and whether what is written actually resolves. The second matters more than it looks —
+ * templates render through nunjucks, which substitutes an unknown variable with the **empty
+ * string**. A typo does not fail loudly, or even leave `{{ }}` behind in the preview; it quietly
+ * drops a value out of the input file a simulation then runs with.
+ *
+ * Kept free of React so the parsing rules are testable on their own.
+ */
+
+/** One entry of the rendering context, as the variables panel lists it. */
+export interface ContextVariable {
+    /** Dotted path to write into a template, e.g. `cutoffs.wavefunction`. */
+    path: string;
+    /** Top-level key the path hangs off, which is what determines its origin. */
+    root: string;
+    origin: string;
+    /** Short rendering of the current value. */
+    preview: string;
+    /** False for objects and arrays, which are containers rather than values. */
+    isLeaf: boolean;
+}
+
+/** A `{{ … }}` expression that will render to nothing. */
+export interface TemplateIssue {
+    /** 1-based, so it matches the editor's gutter. */
+    line: number;
+    /** The whole expression, for showing what was written. */
+    expression: string;
+    /** The longest prefix of the path that does not resolve. */
+    name: string;
+    /** Nearest available name, when one is close enough to be worth offering. */
+    suggestion?: string;
+}
+
+/**
+ * Where a top-level context key comes from.
+ *
+ * wode builds the rendering context as `{ ...providerName → providerData, ...externalContext }`
+ * (`ExecutionUnit.saveRenderingContext`), so anything **not** in this table arrived from a
+ * context provider — which is what the Settings tab edits. That is why the fallback below is a
+ * statement rather than a guess.
+ */
+const EXTERNAL_CONTEXT_ORIGINS: Record = {
+    material: "From the material",
+    materials: "From the material",
+    materialsSet: "From the material",
+    input: "Derived from the material",
+    application: "From the application",
+    methodData: "From the method",
+    subworkflowContext: "Set at job runtime",
+    workflowHasRelaxation: "From the workflow",
+    jobHasParent: "From the workflow",
+};
+
+const PROVIDER_ORIGIN = "Important settings";
+
+export function describeOrigin(root: string, overrides?: Record): string {
+    return overrides?.[root] ?? EXTERNAL_CONTEXT_ORIGINS[root] ?? PROVIDER_ORIGIN;
+}
+
+/** Entity instances (Material, Application…) are opaque here: only plain data is walked. */
+function isPlainObject(value: unknown): value is Record {
+    if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
+    const prototype = Object.getPrototypeOf(value);
+    return prototype === Object.prototype || prototype === null;
+}
+
+function previewValue(value: unknown): string {
+    if (value === null) return "null";
+    if (value === undefined) return "undefined";
+    if (Array.isArray(value)) return `[${value.length} item${value.length === 1 ? "" : "s"}]`;
+    if (typeof value === "object") {
+        const keys = Object.keys(value as Record);
+        return keys.length
+            ? `{ ${keys.slice(0, 3).join(", ")}${keys.length > 3 ? ", …" : ""} }`
+            : "{ }";
+    }
+    const text = String(value);
+    return text.length > 60 ? `${text.slice(0, 57)}…` : text;
+}
+
+export interface FlattenOptions {
+    /** How far to walk into nested plain objects. Deeper paths are still writable by hand. */
+    maxDepth?: number;
+    /** Backstop for a context that turns out to be far larger than expected. */
+    maxVariables?: number;
+    originOverrides?: Record;
+}
+
+/** Every path a template can write, in the order the context declares them. */
+export function flattenRenderingContext(
+    context: Record | undefined,
+    { maxDepth = 3, maxVariables = 400, originOverrides }: FlattenOptions = {},
+): ContextVariable[] {
+    if (!context || typeof context !== "object") return [];
+    const variables: ContextVariable[] = [];
+
+    const walk = (value: unknown, path: string, root: string, depth: number) => {
+        if (variables.length >= maxVariables) return;
+        const isLeaf = !isPlainObject(value) && !Array.isArray(value);
+        variables.push({
+            path,
+            root,
+            origin: describeOrigin(root, originOverrides),
+            preview: previewValue(value),
+            isLeaf,
+        });
+        if (isPlainObject(value) && depth < maxDepth) {
+            Object.keys(value).forEach((key) =>
+                walk(value[key], `${path}.${key}`, root, depth + 1),
+            );
+        }
+    };
+
+    Object.keys(context).forEach((key) => walk(context[key], key, key, 1));
+    return variables;
+}
+
+// ---------------------------------------------------------------------------
+// Template analysis
+// ---------------------------------------------------------------------------
+
+/** Names nunjucks provides itself, plus the operators that read like identifiers. */
+const RESERVED = new Set([
+    "loop",
+    "range",
+    "cycler",
+    "joiner",
+    "super",
+    "self",
+    "true",
+    "false",
+    "none",
+    "null",
+    "True",
+    "False",
+    "None",
+    "if",
+    "else",
+    "elif",
+    "not",
+    "and",
+    "or",
+    "in",
+    "is",
+    "by",
+]);
+
+/**
+ * Blanks out `{% raw %}` bodies, preserving offsets and line breaks.
+ *
+ * What is inside them is deliberately *not* rendered — job-runtime placeholders such as
+ * `{{ JOB_WORK_DIR }}` — so checking them would report the template's whole point as a defect.
+ */
+function blankRawBlocks(template: string): string {
+    return template.replace(/\{%-?\s*raw\s*-?%\}[\s\S]*?\{%-?\s*endraw\s*-?%\}/g, (block) =>
+        block.replace(/[^\n]/g, " "),
+    );
+}
+
+/** Names the template binds itself, which are not expected to be in the context. */
+export function collectLocalNames(template: string): Set {
+    const names = new Set();
+    const add = (name: string) => {
+        const trimmed = name.trim();
+        if (trimmed) names.add(trimmed);
+    };
+
+    Array.from(template.matchAll(/\{%-?\s*(?:set|with)\s+([A-Za-z_]\w*)/g)).forEach((match) =>
+        add(match[1]),
+    );
+    Array.from(template.matchAll(/\{%-?\s*macro\s+([A-Za-z_]\w*)/g)).forEach((match) =>
+        add(match[1]),
+    );
+    // `{% for a, b in items %}` binds both names.
+    Array.from(template.matchAll(/\{%-?\s*for\s+([\s\S]*?)\s+in\s/g)).forEach((match) =>
+        match[1].split(",").forEach(add),
+    );
+    return names;
+}
+
+/** The `{{ … }}` expressions, with the offset each starts at. */
+function extractOutputExpressions(template: string): { expression: string; index: number }[] {
+    return Array.from(template.matchAll(/\{\{([\s\S]*?)\}\}/g)).map((match) => ({
+        expression: match[1],
+        index: match.index ?? 0,
+    }));
+}
+
+/**
+ * Root-anchored dotted paths referenced by an expression.
+ *
+ * Skips string literals, filter names after `|`, property names after `.` whose root was already
+ * skipped, and anything called as a function. Stops a path at `[`, so a dynamic index such as
+ * `input.perMaterial[subworkflowContext.MATERIAL_INDEX]` contributes `input.perMaterial` and the
+ * index expression separately, rather than one path that could never be resolved.
+ */
+export function extractPaths(expression: string): string[] {
+    const paths: string[] = [];
+    let index = 0;
+    let previous = "";
+
+    while (index < expression.length) {
+        const char = expression[index];
+
+        if (char === "'" || char === '"') {
+            const quote = char;
+            index += 1;
+            while (index < expression.length && expression[index] !== quote) {
+                index += expression[index] === "\\" ? 2 : 1;
+            }
+            index += 1;
+            previous = "literal";
+            continue;
+        }
+
+        if (/\s/.test(char)) {
+            index += 1;
+            continue;
+        }
+
+        if (!/[A-Za-z_]/.test(char)) {
+            previous = char;
+            index += 1;
+            continue;
+        }
+
+        let end = index;
+        while (end < expression.length && /\w/.test(expression[end])) end += 1;
+        const identifier = expression.slice(index, end);
+
+        let afterIdentifier = end;
+        while (afterIdentifier < expression.length && /\s/.test(expression[afterIdentifier])) {
+            afterIdentifier += 1;
+        }
+        const isCall = expression[afterIdentifier] === "(";
+        const isSkipped =
+            previous === "|" || previous === "." || isCall || RESERVED.has(identifier);
+
+        if (isSkipped) {
+            index = end;
+            previous = "identifier";
+            continue;
+        }
+
+        let path = identifier;
+        let cursor = end;
+        while (expression[cursor] === ".") {
+            let segmentEnd = cursor + 1;
+            while (segmentEnd < expression.length && /\w/.test(expression[segmentEnd])) {
+                segmentEnd += 1;
+            }
+            if (segmentEnd === cursor + 1) break;
+            let afterSegment = segmentEnd;
+            while (afterSegment < expression.length && /\s/.test(expression[afterSegment])) {
+                afterSegment += 1;
+            }
+            // A method call is not a context path.
+            if (expression[afterSegment] === "(") break;
+            path += `.${expression.slice(cursor + 1, segmentEnd)}`;
+            cursor = segmentEnd;
+        }
+
+        paths.push(path);
+        index = cursor;
+        previous = "identifier";
+    }
+
+    return paths;
+}
+
+interface Resolution {
+    resolved: boolean;
+    /** Longest prefix that failed, when it did. */
+    missing?: string;
+    /** Keys available where it failed, for suggesting a near match. */
+    available?: string[];
+}
+
+/**
+ * Walks a dotted path through the context, stopping the moment it reaches something that is not
+ * plain data — an entity instance's own properties cannot be enumerated reliably, and reporting
+ * `material.name` as missing because `Material` is a class would be worse than saying nothing.
+ */
+export function resolvePath(context: Record, path: string): Resolution {
+    const segments = path.split(".");
+    let current: unknown = context;
+
+    for (let i = 0; i < segments.length; i += 1) {
+        if (!isPlainObject(current)) {
+            return { resolved: true };
+        }
+        if (!(segments[i] in current)) {
+            return {
+                resolved: false,
+                missing: segments.slice(0, i + 1).join("."),
+                available: Object.keys(current),
+            };
+        }
+        current = current[segments[i]];
+    }
+    return { resolved: true };
+}
+
+function editDistance(left: string, right: string): number {
+    const previous = Array.from({ length: right.length + 1 }, (_value, i) => i);
+    for (let i = 1; i <= left.length; i += 1) {
+        let diagonal = previous[0];
+        previous[0] = i;
+        for (let j = 1; j <= right.length; j += 1) {
+            const candidate = Math.min(
+                previous[j] + 1,
+                previous[j - 1] + 1,
+                diagonal + (left[i - 1] === right[j - 1] ? 0 : 1),
+            );
+            diagonal = previous[j];
+            previous[j] = candidate;
+        }
+    }
+    return previous[right.length];
+}
+
+/** Nearest candidate, when one is near enough that offering it is help rather than noise. */
+export function suggestName(name: string, candidates: string[]): string | undefined {
+    let best: { name: string; distance: number } | undefined;
+    candidates.forEach((candidate) => {
+        const distance = editDistance(name.toLowerCase(), candidate.toLowerCase());
+        if (!best || distance < best.distance) best = { name: candidate, distance };
+    });
+    if (!best) return undefined;
+    const limit = name.length <= 4 ? 1 : 2;
+    return best.distance > 0 && best.distance <= limit ? best.name : undefined;
+}
+
+/**
+ * Expressions in `template` that will not resolve against `context`.
+ *
+ * Only `{{ … }}` output is checked, never `{% if … %}` conditions: testing whether an optional
+ * value is present is idiomatic — the templates here open with
+ * `{% if subworkflowContext.MATERIAL_INDEX %}` — while an unresolved `{{ … }}` silently writes an
+ * empty string into the file the simulation runs on.
+ */
+export function findUnresolvedVariables(
+    template: string | undefined,
+    context: Record | undefined,
+): TemplateIssue[] {
+    if (!template || !context) return [];
+
+    const scanned = blankRawBlocks(template);
+    const localNames = collectLocalNames(scanned);
+    const issues: TemplateIssue[] = [];
+    const seen = new Set();
+
+    extractOutputExpressions(scanned).forEach(({ expression, index }) => {
+        const line = scanned.slice(0, index).split("\n").length;
+        extractPaths(expression).forEach((path) => {
+            const [root] = path.split(".");
+            if (localNames.has(root)) return;
+            const resolution = resolvePath(context, path);
+            if (resolution.resolved || !resolution.missing) return;
+            const key = `${line}:${resolution.missing}`;
+            if (seen.has(key)) return;
+            seen.add(key);
+            const missingSegment = resolution.missing.split(".").pop() ?? resolution.missing;
+            const suggestedSegment = suggestName(missingSegment, resolution.available ?? []);
+            const prefix = resolution.missing.split(".").slice(0, -1).join(".");
+            issues.push({
+                line,
+                expression: expression.trim(),
+                name: resolution.missing,
+                ...(suggestedSegment
+                    ? { suggestion: prefix ? `${prefix}.${suggestedSegment}` : suggestedSegment }
+                    : {}),
+            });
+        });
+    });
+
+    return issues;
+}
diff --git a/tests/templateVariables.tests.ts b/tests/templateVariables.tests.ts
new file mode 100644
index 0000000..7ecf532
--- /dev/null
+++ b/tests/templateVariables.tests.ts
@@ -0,0 +1,184 @@
+/* eslint-disable @typescript-eslint/no-floating-promises */
+import assert from "node:assert";
+import test from "node:test";
+
+import {
+    collectLocalNames,
+    describeOrigin,
+    extractPaths,
+    findUnresolvedVariables,
+    flattenRenderingContext,
+    resolvePath,
+    suggestName,
+} from "../src/utils/templateVariables";
+
+/** Shaped like a real execution unit's context: provider data, then the external context. */
+const CONTEXT = {
+    cutoffs: { wavefunction: 40, density: 200 },
+    kgrid: { dimensions: [2, 2, 2], shifts: [0, 0, 0] },
+    input: { IBRAV: 0, NAT: 2, RESTART_MODE: "from_scratch" },
+    material: Object.assign(Object.create({ name: "Si" }), { _json: {} }),
+    materials: [{}],
+    application: { name: "espresso", version: "6.3" },
+    subworkflowContext: {},
+};
+
+test("origins name where a variable came from", () => {
+    assert.strictEqual(describeOrigin("material"), "From the material");
+    assert.strictEqual(describeOrigin("subworkflowContext"), "Set at job runtime");
+    // Not in the external-context table, so wode put it there from a context provider.
+    assert.strictEqual(describeOrigin("cutoffs"), "Important settings");
+    assert.strictEqual(describeOrigin("kgrid"), "Important settings");
+    assert.strictEqual(describeOrigin("cutoffs", { cutoffs: "Custom" }), "Custom");
+    // The external context carries more than the material: these came through the subworkflow,
+    // not through a provider, and mislabelling them sends people to the wrong tab.
+    assert.strictEqual(describeOrigin("materialsSet"), "From the material");
+    assert.strictEqual(describeOrigin("jobHasParent"), "From the workflow");
+});
+
+test("the context flattens to writable dotted paths", () => {
+    const variables = flattenRenderingContext(CONTEXT);
+    const paths = variables.map((variable) => variable.path);
+    assert.ok(paths.includes("cutoffs"));
+    assert.ok(paths.includes("cutoffs.wavefunction"));
+    assert.ok(paths.includes("input.RESTART_MODE"));
+    const wavefunction = variables.find((variable) => variable.path === "cutoffs.wavefunction");
+    assert.strictEqual(wavefunction?.preview, "40");
+    assert.strictEqual(wavefunction?.origin, "Important settings");
+    assert.strictEqual(wavefunction?.isLeaf, true);
+});
+
+test("containers are listed but marked, and arrays report their size", () => {
+    const variables = flattenRenderingContext(CONTEXT);
+    const cutoffs = variables.find((variable) => variable.path === "cutoffs");
+    assert.strictEqual(cutoffs?.isLeaf, false);
+    const dimensions = variables.find((variable) => variable.path === "kgrid.dimensions");
+    assert.strictEqual(dimensions?.preview, "[3 items]");
+});
+
+test("entity instances are one row, not walked", () => {
+    const paths = flattenRenderingContext(CONTEXT).map((variable) => variable.path);
+    assert.ok(paths.includes("material"));
+    assert.ok(!paths.some((path) => path.startsWith("material.")));
+});
+
+test("flattening is bounded by depth and count", () => {
+    const deep = { a: { b: { c: { d: { e: 1 } } } } };
+    const paths = flattenRenderingContext(deep, { maxDepth: 2 }).map((v) => v.path);
+    assert.deepStrictEqual(paths, ["a", "a.b"]);
+    const wide = Object.fromEntries(Array.from({ length: 50 }, (_v, i) => [`k${i}`, i]));
+    assert.strictEqual(flattenRenderingContext(wide, { maxVariables: 10 }).length, 10);
+});
+
+test("an absent context yields nothing rather than throwing", () => {
+    assert.deepStrictEqual(flattenRenderingContext(undefined), []);
+});
+
+test("paths are extracted from an expression, skipping literals and filters", () => {
+    assert.deepStrictEqual(extractPaths(" input.RESTART_MODE "), ["input.RESTART_MODE"]);
+    assert.deepStrictEqual(extractPaths(" cutoffs.wavefunction | round "), [
+        "cutoffs.wavefunction",
+    ]);
+    assert.deepStrictEqual(extractPaths(' "a literal" '), []);
+    assert.deepStrictEqual(extractPaths(" a + b "), ["a", "b"]);
+});
+
+test("a dynamic index contributes the container and the index separately", () => {
+    assert.deepStrictEqual(extractPaths("input.perMaterial[subworkflowContext.MATERIAL_INDEX]"), [
+        "input.perMaterial",
+        "subworkflowContext.MATERIAL_INDEX",
+    ]);
+});
+
+test("a called name is not a context path, but the receiver still is", () => {
+    assert.deepStrictEqual(extractPaths(" range(3) "), []);
+    // `material` has to resolve for the call to work; `getName` is a method, not context data.
+    assert.deepStrictEqual(extractPaths(" material.getName() "), ["material"]);
+    assert.deepStrictEqual(extractPaths(" loop.index "), []);
+});
+
+test("names the template binds itself are collected", () => {
+    const names = collectLocalNames(
+        "{%- set input = input.perMaterial[0] -%}{% for name, value in items %}{% macro row(x) %}",
+    );
+    assert.ok(names.has("input"));
+    assert.ok(names.has("name"));
+    assert.ok(names.has("value"));
+    assert.ok(names.has("row"));
+});
+
+test("resolution walks plain data and gives up at an entity instance", () => {
+    assert.strictEqual(resolvePath(CONTEXT, "cutoffs.wavefunction").resolved, true);
+    // `material` is a class instance: unverifiable, so not reported as missing.
+    assert.strictEqual(resolvePath(CONTEXT, "material.name").resolved, true);
+    const missing = resolvePath(CONTEXT, "cutoffs.wavefunctionn");
+    assert.strictEqual(missing.resolved, false);
+    assert.strictEqual(missing.missing, "cutoffs.wavefunctionn");
+    assert.deepStrictEqual(missing.available, ["wavefunction", "density"]);
+});
+
+test("suggestions are offered only when a name is genuinely close", () => {
+    assert.strictEqual(suggestName("wavefunctionn", ["wavefunction", "density"]), "wavefunction");
+    assert.strictEqual(suggestName("cutofs", ["cutoffs", "kgrid"]), "cutoffs");
+    assert.strictEqual(suggestName("totallyUnrelated", ["cutoffs", "kgrid"]), undefined);
+    // Short names need an exact-ish match, or every three-letter typo suggests every other one.
+    assert.strictEqual(suggestName("abc", ["xyz"]), undefined);
+});
+
+test("a typo'd variable is reported with its line and a suggestion", () => {
+    const template = ["&SYSTEM", "  ecutwfc = {{ cutoffs.wavefunctionn }}", "/"].join("\n");
+    const [issue, ...rest] = findUnresolvedVariables(template, CONTEXT);
+    assert.strictEqual(rest.length, 0);
+    assert.strictEqual(issue.line, 2);
+    assert.strictEqual(issue.name, "cutoffs.wavefunctionn");
+    assert.strictEqual(issue.suggestion, "cutoffs.wavefunction");
+    assert.strictEqual(issue.expression, "cutoffs.wavefunctionn");
+});
+
+test("a valid template reports nothing", () => {
+    const template = [
+        "{% if subworkflowContext.MATERIAL_INDEX %}",
+        "{%- set input = input.perMaterial[subworkflowContext.MATERIAL_INDEX] -%}",
+        "{% endif -%}",
+        "  ecutwfc = {{ cutoffs.wavefunction }}",
+        "  ecutrho = {{ cutoffs.density }}",
+        "  ibrav = {{ input.IBRAV }}",
+        "  nat = {{ input.NAT }}",
+    ].join("\n");
+    assert.deepStrictEqual(findUnresolvedVariables(template, CONTEXT), []);
+});
+
+test("job-runtime placeholders inside raw blocks are left alone", () => {
+    const template = "outdir = {% raw %}'{{ JOB_WORK_DIR }}/outdir'{% endraw %}";
+    assert.deepStrictEqual(findUnresolvedVariables(template, CONTEXT), []);
+});
+
+test("raw blocks do not shift the line numbers of what follows", () => {
+    const template = ["{% raw %}", "{{ JOB_WORK_DIR }}", "{% endraw %}", "{{ nowhere }}"].join(
+        "\n",
+    );
+    const [issue] = findUnresolvedVariables(template, CONTEXT);
+    assert.strictEqual(issue.line, 4);
+    assert.strictEqual(issue.name, "nowhere");
+});
+
+test("an {% if %} test for an absent value is not an issue", () => {
+    const template = "{% if subworkflowContext.NOT_SET %}x{% endif %}";
+    assert.deepStrictEqual(findUnresolvedVariables(template, CONTEXT), []);
+});
+
+test("the same miss on one line is reported once", () => {
+    const template = "{{ nope }} and {{ nope }}";
+    assert.strictEqual(findUnresolvedVariables(template, CONTEXT).length, 1);
+});
+
+test("an unknown root is reported without inventing a suggestion", () => {
+    const [issue] = findUnresolvedVariables("{{ somethingEntirelyElse.x }}", CONTEXT);
+    assert.strictEqual(issue.name, "somethingEntirelyElse");
+    assert.strictEqual(issue.suggestion, undefined);
+});
+
+test("no template or no context means no claims either way", () => {
+    assert.deepStrictEqual(findUnresolvedVariables(undefined, CONTEXT), []);
+    assert.deepStrictEqual(findUnresolvedVariables("{{ nope }}", undefined), []);
+});