diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 731af51..68bc135 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -39,9 +39,7 @@ "@codemirror/view": "^6.38.8", "@cospaia/prettier-plugin-clojure": "^0.0.2", "@lezer/highlight": "^1.2.3", - "@lezer/lr": "^1.4.3", - "@mdit/plugin-katex": "^0.23.2", - "@mdit/plugin-tasklist": "^0.22.2", + "@lezer/lr": "^1.4.4", "@prettier/plugin-xml": "^3.4.2", "@replit/codemirror-lang-svelte": "^6.0.0", "@toml-tools/lexer": "^1.0.0", @@ -54,15 +52,15 @@ "hsl-matcher": "^1.2.4", "java-parser": "^3.0.1", "linguist-languages": "^9.1.0", + "marked": "^17.0.1", "mermaid": "^11.12.1", - "npm": "^11.6.3", "php-parser": "^3.2.5", "pinia": "^3.0.4", "pinia-plugin-persistedstate": "^4.7.1", - "prettier": "^3.6.2", + "prettier": "^3.7.2", "sass": "^1.94.2", - "vue": "^3.5.24", - "vue-i18n": "^11.2.1", + "vue": "^3.5.25", + "vue-i18n": "^11.2.2", "vue-pick-colors": "^1.8.0", "vue-router": "^4.6.3" }, @@ -74,18 +72,18 @@ "@wailsio/runtime": "latest", "cross-env": "^10.1.0", "eslint": "^9.39.1", - "eslint-plugin-vue": "^10.6.0", + "eslint-plugin-vue": "^10.6.2", "globals": "^16.5.0", - "happy-dom": "^20.0.10", + "happy-dom": "^20.0.11", "typescript": "^5.9.3", - "typescript-eslint": "^8.47.0", + "typescript-eslint": "^8.48.0", "unplugin-vue-components": "^30.0.0", "vite": "npm:rolldown-vite@latest", "vite-plugin-node-polyfills": "^0.24.0", "vitepress": "^2.0.0-alpha.12", - "vitest": "^4.0.13", + "vitest": "^4.0.14", "vue-eslint-parser": "^10.2.0", - "vue-tsc": "^3.1.4" + "vue-tsc": "^3.1.5" } }, "node_modules/@antfu/install-pkg": { @@ -1340,13 +1338,13 @@ } }, "node_modules/@intlify/core-base": { - "version": "11.2.1", - "resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-11.2.1.tgz", - "integrity": "sha512-2V1A4yaN9ElAnQ6ih3HHEc+jZ+sHV6BlQHjCsnIVlOotL5NCUgJElIxgUFiJs6zV4puoAq3hHuQIfWNp+J+8yQ==", + "version": "11.2.2", + "resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-11.2.2.tgz", + "integrity": "sha512-0mCTBOLKIqFUP3BzwuFW23hYEl9g/wby6uY//AC5hTgQfTsM2srCYF2/hYGp+a5DZ/HIFIgKkLJMzXTt30r0JQ==", "license": "MIT", "dependencies": { - "@intlify/message-compiler": "11.2.1", - "@intlify/shared": "11.2.1" + "@intlify/message-compiler": "11.2.2", + "@intlify/shared": "11.2.2" }, "engines": { "node": ">= 16" @@ -1356,12 +1354,12 @@ } }, "node_modules/@intlify/message-compiler": { - "version": "11.2.1", - "resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-11.2.1.tgz", - "integrity": "sha512-J2454D3Agg3Kvgaj14gxTleJU8/H06Sisz7C2BwiHF0/i5Soyfb5ySpwn8GCL6yscDbOGj6xM+lUe6gO6BFQyg==", + "version": "11.2.2", + "resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-11.2.2.tgz", + "integrity": "sha512-XS2p8Ff5JxWsKhgfld4/MRQzZRQ85drMMPhb7Co6Be4ZOgqJX1DzcZt0IFgGTycgqL8rkYNwgnD443Q+TapOoA==", "license": "MIT", "dependencies": { - "@intlify/shared": "11.2.1", + "@intlify/shared": "11.2.2", "source-map-js": "^1.0.2" }, "engines": { @@ -1372,9 +1370,9 @@ } }, "node_modules/@intlify/shared": { - "version": "11.2.1", - "resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-11.2.1.tgz", - "integrity": "sha512-O67LZM4dbfr70WCsZLW+g+pIXdgQ66laLVd/FicW7iYgP/RuH0X1FDGSh+Hr9Gou/8TeldUE6KmTGdLwX2ufIA==", + "version": "11.2.2", + "resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-11.2.2.tgz", + "integrity": "sha512-OtCmyFpSXxNu/oET/aN6HtPCbZ01btXVd0f3w00YsHOb13Kverk1jzA2k47pAekM55qbUw421fvPF1yxZ+gicw==", "license": "MIT", "engines": { "node": ">= 16" @@ -1549,9 +1547,9 @@ } }, "node_modules/@lezer/lr": { - "version": "1.4.3", - "resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.3.tgz", - "integrity": "sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA==", + "version": "1.4.4", + "resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.4.tgz", + "integrity": "sha512-LHL17Mq0OcFXm1pGQssuGTQFPPdxARjKM8f7GA5+sGtHi0K3R84YaSbmche0+RKWHnCsx9asEe5OWOI4FHfe4A==", "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" @@ -1639,89 +1637,6 @@ "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", "license": "MIT" }, - "node_modules/@mdit/helper": { - "version": "0.22.1", - "resolved": "https://registry.npmmirror.com/@mdit/helper/-/helper-0.22.1.tgz", - "integrity": "sha512-lDpajcdAk84aYCNAM/Mi3djw38DJq7ocLw5VOSMu/u2YKX3/OD37a6Qb59in8Uyp4SiAbQoSHa8px6hgHEpB5g==", - "license": "MIT", - "dependencies": { - "@types/markdown-it": "^14.1.2" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "markdown-it": "^14.1.0" - }, - "peerDependenciesMeta": { - "markdown-it": { - "optional": true - } - } - }, - "node_modules/@mdit/plugin-katex": { - "version": "0.23.2", - "resolved": "https://registry.npmmirror.com/@mdit/plugin-katex/-/plugin-katex-0.23.2.tgz", - "integrity": "sha512-3914dyl/mHrzrdHDm/ZDhOSUhAttZdF80jKfc1RK5gdTcDSpNekn7naTdeP002oey/bDp1tzooEq5UfbRaHXYg==", - "license": "MIT", - "dependencies": { - "@mdit/helper": "0.22.1", - "@mdit/plugin-tex": "0.22.2", - "@types/markdown-it": "^14.1.2", - "katex": "^0.16.25" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "markdown-it": "^14.1.0" - }, - "peerDependenciesMeta": { - "markdown-it": { - "optional": true - } - } - }, - "node_modules/@mdit/plugin-tasklist": { - "version": "0.22.2", - "resolved": "https://registry.npmmirror.com/@mdit/plugin-tasklist/-/plugin-tasklist-0.22.2.tgz", - "integrity": "sha512-tYxp4tDomTb9NzIphoDXWJxjQZxFuqP4PjU0H9AecUyWuSRP+HICCqe/HVNTTpB0+WDeuVtnxAW9kX08ekxUWw==", - "license": "MIT", - "dependencies": { - "@types/markdown-it": "^14.1.2" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "markdown-it": "^14.1.0" - }, - "peerDependenciesMeta": { - "markdown-it": { - "optional": true - } - } - }, - "node_modules/@mdit/plugin-tex": { - "version": "0.22.2", - "resolved": "https://registry.npmmirror.com/@mdit/plugin-tex/-/plugin-tex-0.22.2.tgz", - "integrity": "sha512-iniJQ9BPZc8AGdLPRoyC+nDA0SoDSe+AETma4y2dOk/EbaSZMYgMaZO843mk5JV7eJkfRc6TWcTIE2CqY2/9Rg==", - "license": "MIT", - "dependencies": { - "@types/markdown-it": "^14.1.2" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "markdown-it": "^14.1.0" - }, - "peerDependenciesMeta": { - "markdown-it": { - "optional": true - } - } - }, "node_modules/@mermaid-js/parser": { "version": "0.6.3", "resolved": "https://registry.npmmirror.com/@mermaid-js/parser/-/parser-0.6.3.tgz", @@ -1731,44 +1646,6 @@ "langium": "3.3.1" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "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.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@nuxt/kit": { "version": "3.17.4", "resolved": "https://registry.npmmirror.com/@nuxt/kit/-/kit-3.17.4.tgz", @@ -2917,18 +2794,6 @@ "@types/d3-selection": "*" } }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@types/ms": "*" - } - }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmmirror.com/@types/deep-eql/-/deep-eql-4.0.2.tgz", @@ -2970,12 +2835,14 @@ "version": "5.0.0", "resolved": "https://registry.npmmirror.com/@types/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, "license": "MIT" }, "node_modules/@types/markdown-it": { "version": "14.1.2", "resolved": "https://registry.npmmirror.com/@types/markdown-it/-/markdown-it-14.1.2.tgz", "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, "license": "MIT", "dependencies": { "@types/linkify-it": "^5", @@ -2996,16 +2863,8 @@ "version": "2.0.0", "resolved": "https://registry.npmmirror.com/@types/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@types/node": { "version": "24.10.1", @@ -3046,17 +2905,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.47.0.tgz", - "integrity": "sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", + "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/type-utils": "8.47.0", - "@typescript-eslint/utils": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/type-utils": "8.48.0", + "@typescript-eslint/utils": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -3070,7 +2929,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.47.0", + "@typescript-eslint/parser": "^8.48.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -3086,16 +2945,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.47.0.tgz", - "integrity": "sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.48.0.tgz", + "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4" }, "engines": { @@ -3111,14 +2970,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.47.0.tgz", - "integrity": "sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.48.0.tgz", + "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.47.0", - "@typescript-eslint/types": "^8.47.0", + "@typescript-eslint/tsconfig-utils": "^8.48.0", + "@typescript-eslint/types": "^8.48.0", "debug": "^4.3.4" }, "engines": { @@ -3133,14 +2992,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.47.0.tgz", - "integrity": "sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz", + "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0" + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3151,9 +3010,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.47.0.tgz", - "integrity": "sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz", + "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==", "dev": true, "license": "MIT", "engines": { @@ -3168,15 +3027,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.47.0.tgz", - "integrity": "sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz", + "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/utils": "8.47.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -3193,9 +3052,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.47.0.tgz", - "integrity": "sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.48.0.tgz", + "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==", "dev": true, "license": "MIT", "engines": { @@ -3207,21 +3066,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.47.0.tgz", - "integrity": "sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz", + "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.47.0", - "@typescript-eslint/tsconfig-utils": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", + "@typescript-eslint/project-service": "8.48.0", + "@typescript-eslint/tsconfig-utils": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", + "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "engines": { @@ -3262,16 +3120,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.47.0.tgz", - "integrity": "sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.48.0.tgz", + "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0" + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3286,13 +3144,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.47.0.tgz", - "integrity": "sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz", + "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", + "@typescript-eslint/types": "8.48.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -3328,16 +3186,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.0.13", - "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-4.0.13.tgz", - "integrity": "sha512-zYtcnNIBm6yS7Gpr7nFTmq8ncowlMdOJkWLqYvhr/zweY6tFbDkDi8BPPOeHxEtK1rSI69H7Fd4+1sqvEGli6w==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-4.0.14.tgz", + "integrity": "sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.13", - "@vitest/utils": "4.0.13", + "@vitest/spy": "4.0.14", + "@vitest/utils": "4.0.14", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" }, @@ -3346,13 +3204,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.0.13", - "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.0.13.tgz", - "integrity": "sha512-eNCwzrI5djoauklwP1fuslHBjrbR8rqIVbvNlAnkq1OTa6XT+lX68mrtPirNM9TnR69XUPt4puBCx2Wexseylg==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.0.14.tgz", + "integrity": "sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.13", + "@vitest/spy": "4.0.14", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -3383,9 +3241,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.0.13", - "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.0.13.tgz", - "integrity": "sha512-ooqfze8URWbI2ozOeLDMh8YZxWDpGXoeY3VOgcDnsUxN0jPyPWSUvjPQWqDGCBks+opWlN1E4oP1UYl3C/2EQA==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.0.14.tgz", + "integrity": "sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3396,13 +3254,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.0.13", - "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-4.0.13.tgz", - "integrity": "sha512-9IKlAru58wcVaWy7hz6qWPb2QzJTKt+IOVKjAx5vb5rzEFPTL6H4/R9BMvjZ2ppkxKgTrFONEJFtzvnyEpiT+A==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-4.0.14.tgz", + "integrity": "sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.13", + "@vitest/utils": "4.0.14", "pathe": "^2.0.3" }, "funding": { @@ -3410,13 +3268,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.0.13", - "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-4.0.13.tgz", - "integrity": "sha512-hb7Usvyika1huG6G6l191qu1urNPsq1iFc2hmdzQY3F5/rTgqQnwwplyf8zoYHkpt7H6rw5UfIw6i/3qf9oSxQ==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-4.0.14.tgz", + "integrity": "sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.13", + "@vitest/pretty-format": "4.0.14", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -3425,9 +3283,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.0.13", - "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-4.0.13.tgz", - "integrity": "sha512-hSu+m4se0lDV5yVIcNWqjuncrmBgwaXa2utFLIrBkQCQkt+pSwyZTPFQAZiiF/63j8jYa8uAeUZ3RSfcdWaYWw==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-4.0.14.tgz", + "integrity": "sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==", "dev": true, "license": "MIT", "funding": { @@ -3435,13 +3293,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.0.13", - "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-4.0.13.tgz", - "integrity": "sha512-ydozWyQ4LZuu8rLp47xFUWis5VOKMdHjXCWhs1LuJsTNKww+pTHQNK4e0assIB9K80TxFyskENL6vCu3j34EYA==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-4.0.14.tgz", + "integrity": "sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.13", + "@vitest/pretty-format": "4.0.14", "tinyrainbow": "^3.0.3" }, "funding": { @@ -3478,39 +3336,39 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.24.tgz", - "integrity": "sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.25.tgz", + "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.24", + "@vue/shared": "3.5.25", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.24.tgz", - "integrity": "sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz", + "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.24", - "@vue/shared": "3.5.24" + "@vue/compiler-core": "3.5.25", + "@vue/shared": "3.5.25" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.24.tgz", - "integrity": "sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz", + "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==", "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.24", - "@vue/compiler-dom": "3.5.24", - "@vue/compiler-ssr": "3.5.24", - "@vue/shared": "3.5.24", + "@vue/compiler-core": "3.5.25", + "@vue/compiler-dom": "3.5.25", + "@vue/compiler-ssr": "3.5.25", + "@vue/shared": "3.5.25", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", @@ -3518,13 +3376,13 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.24.tgz", - "integrity": "sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", + "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.24", - "@vue/shared": "3.5.24" + "@vue/compiler-dom": "3.5.25", + "@vue/shared": "3.5.25" } }, "node_modules/@vue/devtools-api": { @@ -3561,9 +3419,9 @@ } }, "node_modules/@vue/language-core": { - "version": "3.1.4", - "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.1.4.tgz", - "integrity": "sha512-n/58wm8SkmoxMWkUNUH/PwoovWe4hmdyPJU2ouldr3EPi1MLoS7iDN46je8CsP95SnVBs2axInzRglPNKvqMcg==", + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.1.5.tgz", + "integrity": "sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==", "dev": true, "license": "MIT", "dependencies": { @@ -3598,53 +3456,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.24.tgz", - "integrity": "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.25.tgz", + "integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.24" + "@vue/shared": "3.5.25" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.24.tgz", - "integrity": "sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.25.tgz", + "integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.24", - "@vue/shared": "3.5.24" + "@vue/reactivity": "3.5.25", + "@vue/shared": "3.5.25" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.24.tgz", - "integrity": "sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.25.tgz", + "integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.24", - "@vue/runtime-core": "3.5.24", - "@vue/shared": "3.5.24", + "@vue/reactivity": "3.5.25", + "@vue/runtime-core": "3.5.25", + "@vue/shared": "3.5.25", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.24.tgz", - "integrity": "sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.25.tgz", + "integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.24", - "@vue/shared": "3.5.24" + "@vue/compiler-ssr": "3.5.25", + "@vue/shared": "3.5.25" }, "peerDependencies": { - "vue": "3.5.24" + "vue": "3.5.25" } }, "node_modules/@vue/shared": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.24.tgz", - "integrity": "sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.25.tgz", + "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==", "license": "MIT" }, "node_modules/@vueuse/core": { @@ -3820,9 +3678,9 @@ } }, "node_modules/alien-signals": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-3.1.0.tgz", - "integrity": "sha512-yufC6VpSy8tK3I0lO67pjumo5JvDQVQyr38+3OHqe6CHl1t2VZekKZ7EKKZSqk0cRmE7U7tfZbpXiKNzuc+ckg==", + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-3.1.1.tgz", + "integrity": "sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==", "dev": true, "license": "MIT" }, @@ -3846,7 +3704,7 @@ "version": "2.0.1", "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "devOptional": true, + "dev": true, "license": "Python-2.0" }, "node_modules/asn1.js": { @@ -3974,8 +3832,8 @@ "version": "3.0.3", "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -4679,9 +4537,9 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "node_modules/cytoscape": { @@ -5597,9 +5455,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "10.6.0", - "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.6.0.tgz", - "integrity": "sha512-TsoFluWxOpsJlE/l2jJygLQLWBPJ3Qdkesv7tBIunICbTcG0dS1/NBw/Ol4tJw5kHWlAVds4lUmC29/vlPUcEQ==", + "version": "10.6.2", + "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.6.2.tgz", + "integrity": "sha512-nA5yUs/B1KmKzvC42fyD0+l9Yd+LtEpVhWRbXuDj0e+ZURcTtyRbMDWUeJmTAh2wC6jC83raS63anNM2YT3NPw==", "dev": true, "license": "MIT", "dependencies": { @@ -5772,36 +5630,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -5816,16 +5644,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -5843,8 +5661,8 @@ "version": "7.1.1", "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -6058,9 +5876,9 @@ "license": "MIT" }, "node_modules/happy-dom": { - "version": "20.0.10", - "resolved": "https://registry.npmmirror.com/happy-dom/-/happy-dom-20.0.10.tgz", - "integrity": "sha512-6umCCHcjQrhP5oXhrHQQvLB0bwb1UzHAHdsXy+FjtKoYjUhmNZsQL8NivwM1vDvNEChJabVrUYxUnp/ZdYmy2g==", + "version": "20.0.11", + "resolved": "https://registry.npmmirror.com/happy-dom/-/happy-dom-20.0.11.tgz", + "integrity": "sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==", "dev": true, "license": "MIT", "dependencies": { @@ -6466,8 +6284,8 @@ "version": "7.0.0", "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.12.0" } @@ -6720,17 +6538,6 @@ "integrity": "sha512-rsfEA3KUoRBB1rNttxAqq23/vzHtsN9EGegzVV3FWom1sWNyUZDhqHjb9fP/UJSFKisteVrSpI2NGf+AdXhYMQ==", "license": "MIT" }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "uc.micro": "^2.0.0" - } - }, "node_modules/local-pkg": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.2.tgz", @@ -6799,29 +6606,10 @@ "dev": true, "license": "MIT" }, - "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, "node_modules/marked": { - "version": "16.4.2", - "resolved": "https://registry.npmmirror.com/marked/-/marked-16.4.2.tgz", - "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "version": "17.0.1", + "resolved": "https://registry.npmmirror.com/marked/-/marked-17.0.1.tgz", + "integrity": "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -6874,24 +6662,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/mermaid": { "version": "11.12.1", "resolved": "https://registry.npmmirror.com/mermaid/-/mermaid-11.12.1.tgz", @@ -6920,6 +6690,18 @@ "uuid": "^11.1.0" } }, + "node_modules/mermaid/node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmmirror.com/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/micromark-util-character": { "version": "2.1.1", "resolved": "https://registry.npmmirror.com/micromark-util-character/-/micromark-util-character-2.1.1.tgz", @@ -7018,8 +6800,8 @@ "version": "4.0.8", "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -7217,2290 +6999,6 @@ "dev": true, "license": "MIT" }, - "node_modules/npm": { - "version": "11.6.3", - "resolved": "https://registry.npmmirror.com/npm/-/npm-11.6.3.tgz", - "integrity": "sha512-QIWnYxYuDjrNGaTp0jrTqgl45QHM+UfdcjPBKmia4LsBkHY8TvEjZpkAVrNO7EOJA//tOP3k+9cioXwqdAfukg==", - "bundleDependencies": [ - "@isaacs/string-locale-compare", - "@npmcli/arborist", - "@npmcli/config", - "@npmcli/fs", - "@npmcli/map-workspaces", - "@npmcli/metavuln-calculator", - "@npmcli/package-json", - "@npmcli/promise-spawn", - "@npmcli/redact", - "@npmcli/run-script", - "@sigstore/tuf", - "abbrev", - "archy", - "cacache", - "chalk", - "ci-info", - "cli-columns", - "fastest-levenshtein", - "fs-minipass", - "glob", - "graceful-fs", - "hosted-git-info", - "ini", - "init-package-json", - "is-cidr", - "json-parse-even-better-errors", - "libnpmaccess", - "libnpmdiff", - "libnpmexec", - "libnpmfund", - "libnpmorg", - "libnpmpack", - "libnpmpublish", - "libnpmsearch", - "libnpmteam", - "libnpmversion", - "make-fetch-happen", - "minimatch", - "minipass", - "minipass-pipeline", - "ms", - "node-gyp", - "nopt", - "npm-audit-report", - "npm-install-checks", - "npm-package-arg", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "p-map", - "pacote", - "parse-conflict-json", - "proc-log", - "qrcode-terminal", - "read", - "semver", - "spdx-expression-parse", - "ssri", - "supports-color", - "tar", - "text-table", - "tiny-relative-date", - "treeverse", - "validate-npm-package-name", - "which" - ], - "license": "Artistic-2.0", - "workspaces": [ - "docs", - "smoke-tests", - "mock-globals", - "mock-registry", - "workspaces/*" - ], - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^9.1.7", - "@npmcli/config": "^10.4.3", - "@npmcli/fs": "^4.0.0", - "@npmcli/map-workspaces": "^5.0.1", - "@npmcli/metavuln-calculator": "^9.0.3", - "@npmcli/package-json": "^7.0.2", - "@npmcli/promise-spawn": "^9.0.1", - "@npmcli/redact": "^4.0.0", - "@npmcli/run-script": "^10.0.3", - "@sigstore/tuf": "^4.0.0", - "abbrev": "^4.0.0", - "archy": "~1.0.0", - "cacache": "^20.0.2", - "chalk": "^5.6.2", - "ci-info": "^4.3.1", - "cli-columns": "^4.0.0", - "fastest-levenshtein": "^1.0.16", - "fs-minipass": "^3.0.3", - "glob": "^11.0.3", - "graceful-fs": "^4.2.11", - "hosted-git-info": "^9.0.2", - "ini": "^6.0.0", - "init-package-json": "^8.2.3", - "is-cidr": "^6.0.1", - "json-parse-even-better-errors": "^5.0.0", - "libnpmaccess": "^10.0.3", - "libnpmdiff": "^8.0.10", - "libnpmexec": "^10.1.9", - "libnpmfund": "^7.0.10", - "libnpmorg": "^8.0.1", - "libnpmpack": "^9.0.10", - "libnpmpublish": "^11.1.3", - "libnpmsearch": "^9.0.1", - "libnpmteam": "^8.0.2", - "libnpmversion": "^8.0.3", - "make-fetch-happen": "^15.0.3", - "minimatch": "^10.1.1", - "minipass": "^7.1.1", - "minipass-pipeline": "^1.2.4", - "ms": "^2.1.2", - "node-gyp": "^12.1.0", - "nopt": "^9.0.0", - "npm-audit-report": "^6.0.0", - "npm-install-checks": "^8.0.0", - "npm-package-arg": "^13.0.2", - "npm-pick-manifest": "^11.0.3", - "npm-profile": "^12.0.1", - "npm-registry-fetch": "^19.1.1", - "npm-user-validate": "^3.0.0", - "p-map": "^7.0.3", - "pacote": "^21.0.4", - "parse-conflict-json": "^5.0.1", - "proc-log": "^6.0.0", - "qrcode-terminal": "^0.12.0", - "read": "^4.1.0", - "semver": "^7.7.3", - "spdx-expression-parse": "^4.0.0", - "ssri": "^13.0.0", - "supports-color": "^10.2.2", - "tar": "^7.5.2", - "text-table": "~0.2.0", - "tiny-relative-date": "^2.0.2", - "treeverse": "^3.0.0", - "validate-npm-package-name": "^7.0.0", - "which": "^6.0.0" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/npm/node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/npm/node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/@npmcli/agent": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^11.2.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "9.1.7", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^4.0.0", - "@npmcli/installed-package-contents": "^4.0.0", - "@npmcli/map-workspaces": "^5.0.0", - "@npmcli/metavuln-calculator": "^9.0.2", - "@npmcli/name-from-folder": "^4.0.0", - "@npmcli/node-gyp": "^5.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/query": "^4.0.0", - "@npmcli/redact": "^4.0.0", - "@npmcli/run-script": "^10.0.0", - "bin-links": "^6.0.0", - "cacache": "^20.0.1", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^9.0.0", - "json-stringify-nice": "^1.1.4", - "lru-cache": "^11.2.1", - "minimatch": "^10.0.3", - "nopt": "^8.0.0", - "npm-install-checks": "^8.0.0", - "npm-package-arg": "^13.0.0", - "npm-pick-manifest": "^11.0.1", - "npm-registry-fetch": "^19.0.0", - "pacote": "^21.0.2", - "parse-conflict-json": "^5.0.1", - "proc-log": "^6.0.0", - "proggy": "^3.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^3.0.1", - "semver": "^7.3.7", - "ssri": "^13.0.0", - "treeverse": "^3.0.0", - "walk-up-path": "^4.0.0" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/config": { - "version": "10.4.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/map-workspaces": "^5.0.0", - "@npmcli/package-json": "^7.0.0", - "ci-info": "^4.0.0", - "ini": "^6.0.0", - "nopt": "^8.1.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "walk-up-path": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/fs": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/git": { - "version": "7.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^9.0.0", - "ini": "^6.0.0", - "lru-cache": "^11.2.1", - "npm-pick-manifest": "^11.0.1", - "proc-log": "^6.0.0", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^5.0.0", - "npm-normalize-package-bin": "^5.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "5.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^4.0.0", - "@npmcli/package-json": "^7.0.0", - "glob": "^11.0.3", - "minimatch": "^10.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "9.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cacache": "^20.0.0", - "json-parse-even-better-errors": "^5.0.0", - "pacote": "^21.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "7.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^7.0.0", - "glob": "^11.0.3", - "hosted-git-info": "^9.0.0", - "json-parse-even-better-errors": "^5.0.0", - "proc-log": "^6.0.0", - "semver": "^7.5.3", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "9.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "which": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/query": { - "version": "4.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/redact": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "10.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^5.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/promise-spawn": "^9.0.0", - "node-gyp": "^12.1.0", - "proc-log": "^6.0.0", - "which": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@sigstore/bundle": { - "version": "4.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.5.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@sigstore/core": { - "version": "3.0.0", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.5.0", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/sign": { - "version": "4.0.1", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", - "@sigstore/protobuf-specs": "^0.5.0", - "make-fetch-happen": "^15.0.2", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@sigstore/sign/node_modules/proc-log": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "4.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.5.0", - "tuf-js": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@sigstore/verify": { - "version": "3.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", - "@sigstore/protobuf-specs": "^0.5.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/@tufjs/models": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/abbrev": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/agent-base": { - "version": "7.1.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/ansi-regex": { - "version": "5.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "6.2.3", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/aproba": { - "version": "2.1.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/bin-links": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^8.0.0", - "npm-normalize-package-bin": "^5.0.0", - "proc-log": "^6.0.0", - "read-cmd-shim": "^6.0.0", - "write-file-atomic": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/binary-extensions": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=18.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "2.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/npm/node_modules/cacache": { - "version": "20.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^11.0.3", - "lru-cache": "^11.1.0", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^13.0.0", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/chalk": { - "version": "5.6.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/npm/node_modules/chownr": { - "version": "3.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/ci-info": { - "version": "4.3.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "5.0.1", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "ip-regex": "5.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/npm/node_modules/cli-columns": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/cmd-shim": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.4", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/common-ancestor-path": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/cross-spawn": { - "version": "7.0.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cross-spawn/node_modules/isexe": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cssesc": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/debug": { - "version": "4.4.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/npm/node_modules/diff": { - "version": "8.0.2", - "inBundle": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/npm/node_modules/eastasianwidth": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/emoji-regex": { - "version": "8.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/encoding": { - "version": "0.1.13", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/npm/node_modules/env-paths": { - "version": "2.2.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/err-code": { - "version": "2.0.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/exponential-backoff": { - "version": "3.1.3", - "inBundle": true, - "license": "Apache-2.0" - }, - "node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.16", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/npm/node_modules/foreground-child": { - "version": "3.3.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "3.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/glob": { - "version": "11.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.0.3", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.11", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/hosted-git-info": { - "version": "9.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^11.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.2.0", - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/http-proxy-agent": { - "version": "7.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/https-proxy-agent": { - "version": "7.0.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/iconv-lite": { - "version": "0.6.3", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/ignore-walk": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minimatch": "^10.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/npm/node_modules/ini": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/init-package-json": { - "version": "8.2.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/package-json": "^7.0.0", - "npm-package-arg": "^13.0.0", - "promzard": "^2.0.0", - "read": "^4.0.0", - "semver": "^7.7.2", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/ip-address": { - "version": "10.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/npm/node_modules/ip-regex": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/is-cidr": { - "version": "6.0.1", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "cidr-regex": "5.0.1" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/isexe": { - "version": "3.1.1", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/npm/node_modules/jackspeak": { - "version": "4.1.1", - "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/json-stringify-nice": { - "version": "1.1.4", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff": { - "version": "6.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff-apply": { - "version": "5.5.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/libnpmaccess": { - "version": "10.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^13.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmdiff": { - "version": "8.0.10", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.1.7", - "@npmcli/installed-package-contents": "^3.0.0", - "binary-extensions": "^3.0.0", - "diff": "^8.0.2", - "minimatch": "^10.0.3", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2", - "tar": "^7.5.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmexec": { - "version": "10.1.9", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.1.7", - "@npmcli/package-json": "^7.0.0", - "@npmcli/run-script": "^10.0.0", - "ci-info": "^4.0.0", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2", - "proc-log": "^6.0.0", - "promise-retry": "^2.0.1", - "read": "^4.0.0", - "semver": "^7.3.7", - "signal-exit": "^4.1.0", - "walk-up-path": "^4.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmfund": { - "version": "7.0.10", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.1.7" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmorg": { - "version": "8.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmpack": { - "version": "9.0.10", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^9.1.7", - "@npmcli/run-script": "^10.0.0", - "npm-package-arg": "^13.0.0", - "pacote": "^21.0.2" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmpublish": { - "version": "11.1.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/package-json": "^7.0.0", - "ci-info": "^4.0.0", - "npm-package-arg": "^13.0.0", - "npm-registry-fetch": "^19.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.7", - "sigstore": "^4.0.0", - "ssri": "^13.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmsearch": { - "version": "9.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmteam": { - "version": "8.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^19.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/libnpmversion": { - "version": "8.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^7.0.0", - "@npmcli/run-script": "^10.0.0", - "json-parse-even-better-errors": "^5.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/lru-cache": { - "version": "11.2.2", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/npm/node_modules/make-fetch-happen": { - "version": "15.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/agent": "^4.0.0", - "cacache": "^20.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^5.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^6.0.0", - "promise-retry": "^2.0.1", - "ssri": "^13.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/minimatch": { - "version": "10.1.1", - "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/minipass": { - "version": "7.1.2", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/minipass-collect": { - "version": "2.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/minipass-fetch": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^3.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm/node_modules/minipass-flush": { - "version": "1.0.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minizlib": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/mute-stream": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/negotiator": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/node-gyp": { - "version": "12.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^15.0.0", - "nopt": "^9.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "tar": "^7.5.2", - "tinyglobby": "^0.2.12", - "which": "^6.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/nopt": { - "version": "9.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "^4.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-audit-report": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-bundled": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-install-checks": { - "version": "8.0.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-package-arg": { - "version": "13.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^9.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-packlist": { - "version": "10.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "ignore-walk": "^8.0.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "11.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^8.0.0", - "npm-normalize-package-bin": "^5.0.0", - "npm-package-arg": "^13.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-profile": { - "version": "12.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^19.0.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "19.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/redact": "^4.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^15.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^5.0.0", - "minizlib": "^3.0.1", - "npm-package-arg": "^13.0.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/npm-user-validate": { - "version": "3.0.0", - "inBundle": true, - "license": "BSD-2-Clause", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/p-map": { - "version": "7.0.3", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/package-json-from-dist": { - "version": "1.0.1", - "inBundle": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/npm/node_modules/pacote": { - "version": "21.0.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^7.0.0", - "@npmcli/installed-package-contents": "^4.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/promise-spawn": "^9.0.0", - "@npmcli/run-script": "^10.0.0", - "cacache": "^20.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^13.0.0", - "npm-packlist": "^10.0.1", - "npm-pick-manifest": "^11.0.1", - "npm-registry-fetch": "^19.0.0", - "proc-log": "^6.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^4.0.0", - "ssri": "^13.0.0", - "tar": "^7.4.3" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/parse-conflict-json": { - "version": "5.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^5.0.0", - "just-diff": "^6.0.0", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/path-key": { - "version": "3.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/path-scurry": { - "version": "2.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/proc-log": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/proggy": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/promise-all-reject-late": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-call-limit": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-retry": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/promzard": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "read": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", - "inBundle": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/npm/node_modules/read": { - "version": "4.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "mute-stream": "^2.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/npm/node_modules/semver": { - "version": "7.7.3", - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/shebang-command": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/shebang-regex": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/signal-exit": { - "version": "4.1.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/sigstore": { - "version": "4.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", - "@sigstore/protobuf-specs": "^0.5.0", - "@sigstore/sign": "^4.0.0", - "@sigstore/tuf": "^4.0.0", - "@sigstore/verify": "^3.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/smart-buffer": { - "version": "4.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks": { - "version": "2.8.7", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.5", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/spdx-correct": { - "version": "3.2.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.5.0", - "inBundle": true, - "license": "CC-BY-3.0" - }, - "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.22", - "inBundle": true, - "license": "CC0-1.0" - }, - "node_modules/npm/node_modules/ssri": { - "version": "13.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/string-width": { - "version": "4.2.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/strip-ansi": { - "version": "6.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/supports-color": { - "version": "10.2.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/npm/node_modules/tar": { - "version": "7.5.2", - "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/tar/node_modules/yallist": { - "version": "5.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tiny-relative-date": { - "version": "2.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tinyglobby": { - "version": "0.2.15", - "inBundle": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/npm/node_modules/treeverse": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/tuf-js": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "@tufjs/models": "4.0.0", - "debug": "^4.4.1", - "make-fetch-happen": "^15.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/unique-filename": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/unique-slug": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/util-deprecate": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/walk-up-path": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/npm/node_modules/which": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/wrap-ansi": { - "version": "8.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm/node_modules/yallist": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC" - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz", @@ -9596,6 +7094,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/ohash": { "version": "2.0.11", "resolved": "https://registry.npmmirror.com/ohash/-/ohash-2.0.11.tgz", @@ -9844,8 +7353,8 @@ "version": "2.3.1", "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8.6" }, @@ -10002,9 +7511,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.7.2", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.7.2.tgz", + "integrity": "sha512-n3HV2J6QhItCXndGa3oMWvWFAgN1ibnS7R9mt6iokScBOC0Ul9/iZORmU2IWUMcyAQaMPjTlY3uT34TqocUxMA==", "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -10076,17 +7585,6 @@ "node": ">=6" } }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmmirror.com/qs/-/qs-6.14.0.tgz", @@ -10128,27 +7626,6 @@ "node": ">=0.4.x" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/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" - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", @@ -10274,17 +7751,6 @@ "node": ">=4" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", @@ -10360,30 +7826,6 @@ "points-on-path": "^0.2.1" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/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", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmmirror.com/rw/-/rw-1.3.3.tgz", @@ -10949,8 +8391,8 @@ "version": "5.0.1", "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -11041,16 +8483,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.47.0.tgz", - "integrity": "sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==", + "version": "8.48.0", + "resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.48.0.tgz", + "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.47.0", - "@typescript-eslint/parser": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/utils": "8.47.0" + "@typescript-eslint/eslint-plugin": "8.48.0", + "@typescript-eslint/parser": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -11064,14 +8506,6 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/ufo": { "version": "1.6.1", "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.6.1.tgz", @@ -11702,23 +9136,23 @@ "license": "MIT" }, "node_modules/vitest": { - "version": "4.0.13", - "resolved": "https://registry.npmmirror.com/vitest/-/vitest-4.0.13.tgz", - "integrity": "sha512-QSD4I0fN6uZQfftryIXuqvqgBxTvJ3ZNkF6RWECd82YGAYAfhcppBLFXzXJHQAAhVFyYEuFTrq6h0hQqjB7jIQ==", + "version": "4.0.14", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-4.0.14.tgz", + "integrity": "sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.0.13", - "@vitest/mocker": "4.0.13", - "@vitest/pretty-format": "4.0.13", - "@vitest/runner": "4.0.13", - "@vitest/snapshot": "4.0.13", - "@vitest/spy": "4.0.13", - "@vitest/utils": "4.0.13", - "debug": "^4.4.3", + "@vitest/expect": "4.0.14", + "@vitest/mocker": "4.0.14", + "@vitest/pretty-format": "4.0.14", + "@vitest/runner": "4.0.14", + "@vitest/snapshot": "4.0.14", + "@vitest/spy": "4.0.14", + "@vitest/utils": "4.0.14", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", + "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", @@ -11741,12 +9175,11 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", - "@types/debug": "^4.1.12", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.13", - "@vitest/browser-preview": "4.0.13", - "@vitest/browser-webdriverio": "4.0.13", - "@vitest/ui": "4.0.13", + "@vitest/browser-playwright": "4.0.14", + "@vitest/browser-preview": "4.0.14", + "@vitest/browser-webdriverio": "4.0.14", + "@vitest/ui": "4.0.14", "happy-dom": "*", "jsdom": "*" }, @@ -11757,9 +9190,6 @@ "@opentelemetry/api": { "optional": true }, - "@types/debug": { - "optional": true - }, "@types/node": { "optional": true }, @@ -11854,16 +9284,16 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.24", - "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.24.tgz", - "integrity": "sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg==", + "version": "3.5.25", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.25.tgz", + "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.24", - "@vue/compiler-sfc": "3.5.24", - "@vue/runtime-dom": "3.5.24", - "@vue/server-renderer": "3.5.24", - "@vue/shared": "3.5.24" + "@vue/compiler-dom": "3.5.25", + "@vue/compiler-sfc": "3.5.25", + "@vue/runtime-dom": "3.5.25", + "@vue/server-renderer": "3.5.25", + "@vue/shared": "3.5.25" }, "peerDependencies": { "typescript": "*" @@ -11899,13 +9329,13 @@ } }, "node_modules/vue-i18n": { - "version": "11.2.1", - "resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-11.2.1.tgz", - "integrity": "sha512-cc3Wx4eJZac9WMS8mxhfYiCipm9PBQ2Dz15piWYm7DwNcCehaKRgpolEdiqrjjT27T3Wijz3xJ7NeIc8ofIWAA==", + "version": "11.2.2", + "resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-11.2.2.tgz", + "integrity": "sha512-ULIKZyRluUPRCZmihVgUvpq8hJTtOqnbGZuv4Lz+byEKZq4mU0g92og414l6f/4ju+L5mORsiUuEPYrAuX2NJg==", "license": "MIT", "dependencies": { - "@intlify/core-base": "11.2.1", - "@intlify/shared": "11.2.1", + "@intlify/core-base": "11.2.2", + "@intlify/shared": "11.2.2", "@vue/devtools-api": "^6.5.0" }, "engines": { @@ -11959,14 +9389,14 @@ "license": "MIT" }, "node_modules/vue-tsc": { - "version": "3.1.4", - "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.1.4.tgz", - "integrity": "sha512-GsRJxttj4WkmXW/zDwYPGMJAN3np/4jTzoDFQTpTsI5Vg/JKMWamBwamlmLihgSVHO66y9P7GX+uoliYxeI4Hw==", + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.1.5.tgz", + "integrity": "sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==", "dev": true, "license": "MIT", "dependencies": { "@volar/typescript": "2.4.23", - "@vue/language-core": "3.1.4" + "@vue/language-core": "3.1.5" }, "bin": { "vue-tsc": "bin/vue-tsc.js" diff --git a/frontend/package.json b/frontend/package.json index 61ad5eb..49b79d3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,9 +53,7 @@ "@codemirror/view": "^6.38.8", "@cospaia/prettier-plugin-clojure": "^0.0.2", "@lezer/highlight": "^1.2.3", - "@lezer/lr": "^1.4.3", - "@mdit/plugin-katex": "^0.23.2", - "@mdit/plugin-tasklist": "^0.22.2", + "@lezer/lr": "^1.4.4", "@prettier/plugin-xml": "^3.4.2", "@replit/codemirror-lang-svelte": "^6.0.0", "@toml-tools/lexer": "^1.0.0", @@ -68,15 +66,15 @@ "hsl-matcher": "^1.2.4", "java-parser": "^3.0.1", "linguist-languages": "^9.1.0", + "marked": "^17.0.1", "mermaid": "^11.12.1", - "npm": "^11.6.3", "php-parser": "^3.2.5", "pinia": "^3.0.4", "pinia-plugin-persistedstate": "^4.7.1", - "prettier": "^3.6.2", + "prettier": "^3.7.2", "sass": "^1.94.2", - "vue": "^3.5.24", - "vue-i18n": "^11.2.1", + "vue": "^3.5.25", + "vue-i18n": "^11.2.2", "vue-pick-colors": "^1.8.0", "vue-router": "^4.6.3" }, @@ -88,18 +86,18 @@ "@wailsio/runtime": "latest", "cross-env": "^10.1.0", "eslint": "^9.39.1", - "eslint-plugin-vue": "^10.6.0", + "eslint-plugin-vue": "^10.6.2", "globals": "^16.5.0", - "happy-dom": "^20.0.10", + "happy-dom": "^20.0.11", "typescript": "^5.9.3", - "typescript-eslint": "^8.47.0", + "typescript-eslint": "^8.48.0", "unplugin-vue-components": "^30.0.0", "vite": "npm:rolldown-vite@latest", "vite-plugin-node-polyfills": "^0.24.0", "vitepress": "^2.0.0-alpha.12", - "vitest": "^4.0.13", + "vitest": "^4.0.14", "vue-eslint-parser": "^10.2.0", - "vue-tsc": "^3.1.4" + "vue-tsc": "^3.1.5" }, "overrides": { "vite": "npm:rolldown-vite@latest" diff --git a/frontend/src/assets/styles/variables.css b/frontend/src/assets/styles/variables.css index 43b85fb..896362e 100644 --- a/frontend/src/assets/styles/variables.css +++ b/frontend/src/assets/styles/variables.css @@ -61,6 +61,19 @@ /* Markdown 内联代码样式 */ --cm-inline-code-bg: oklch(28% 0.02 255); + + /* Markdown 上标/下标样式 */ + --cm-superscript-color: inherit; + --cm-subscript-color: inherit; + + /* Markdown 高亮样式 */ + --cm-highlight-background: rgba(250, 204, 21, 0.35); + + /* Markdown 脚注样式 */ + --cm-footnote-ref-color: #818cf8; + --cm-footnote-ref-hover-bg: rgba(129, 140, 248, 0.15); + --cm-footnote-undefined-color: #f87171; + --cm-footnote-def-color: #818cf8; } /* 亮色主题 */ @@ -120,6 +133,19 @@ /* Markdown 内联代码样式 */ --cm-inline-code-bg: oklch(92.9% 0.013 255.508); + + /* Markdown 上标/下标样式 */ + --cm-superscript-color: inherit; + --cm-subscript-color: inherit; + + /* Markdown 高亮样式 */ + --cm-highlight-background: rgba(253, 224, 71, 0.45); + + /* Markdown 脚注样式 */ + --cm-footnote-ref-color: #6366f1; + --cm-footnote-ref-hover-bg: rgba(99, 102, 241, 0.15); + --cm-footnote-undefined-color: #ef4444; + --cm-footnote-def-color: #6366f1; } /* 跟随系统的浅色偏好 */ @@ -180,5 +206,18 @@ /* Markdown 内联代码样式 */ --cm-inline-code-bg: oklch(92.9% 0.013 255.508); + + /* Markdown 上标/下标样式 */ + --cm-superscript-color: inherit; + --cm-subscript-color: inherit; + + /* Markdown 高亮样式 */ + --cm-highlight-background: rgba(253, 224, 71, 0.45); + + /* Markdown 脚注样式 */ + --cm-footnote-ref-color: #6366f1; + --cm-footnote-ref-hover-bg: rgba(99, 102, 241, 0.15); + --cm-footnote-undefined-color: #ef4444; + --cm-footnote-def-color: #6366f1; } } diff --git a/frontend/src/common/constant/emojies.ts b/frontend/src/common/constant/emojies.ts new file mode 100644 index 0000000..5939148 --- /dev/null +++ b/frontend/src/common/constant/emojies.ts @@ -0,0 +1,1945 @@ +export interface EmojiDefs { + [key: string]: string; +} + +export const emojies: EmojiDefs = { + "100": "💯", + "1234": "🔢", + "grinning": "😀", + "smiley": "😃", + "smile": "😄", + "grin": "😁", + "laughing": "😆", + "satisfied": "😆", + "sweat_smile": "😅", + "rofl": "🤣", + "joy": "😂", + "slightly_smiling_face": "🙂", + "upside_down_face": "🙃", + "melting_face": "🫠", + "wink": "😉", + "blush": "😊", + "innocent": "😇", + "smiling_face_with_three_hearts": "🥰", + "heart_eyes": "😍", + "star_struck": "🤩", + "kissing_heart": "😘", + "kissing": "😗", + "relaxed": "☺️", + "kissing_closed_eyes": "😚", + "kissing_smiling_eyes": "😙", + "smiling_face_with_tear": "🥲", + "yum": "😋", + "stuck_out_tongue": "😛", + "stuck_out_tongue_winking_eye": "😜", + "zany_face": "🤪", + "stuck_out_tongue_closed_eyes": "😝", + "money_mouth_face": "🤑", + "hugs": "🤗", + "hand_over_mouth": "🤭", + "face_with_open_eyes_and_hand_over_mouth": "🫢", + "face_with_peeking_eye": "🫣", + "shushing_face": "🤫", + "thinking": "🤔", + "saluting_face": "🫡", + "zipper_mouth_face": "🤐", + "raised_eyebrow": "🤨", + "neutral_face": "😐", + "expressionless": "😑", + "no_mouth": "😶", + "dotted_line_face": "🫥", + "face_in_clouds": "😶‍🌫️", + "smirk": "😏", + "unamused": "😒", + "roll_eyes": "🙄", + "grimacing": "😬", + "face_exhaling": "😮‍💨", + "lying_face": "🤥", + "shaking_face": "🫨", + "relieved": "😌", + "pensive": "😔", + "sleepy": "😪", + "drooling_face": "🤤", + "sleeping": "😴", + "mask": "😷", + "face_with_thermometer": "🤒", + "face_with_head_bandage": "🤕", + "nauseated_face": "🤢", + "vomiting_face": "🤮", + "sneezing_face": "🤧", + "hot_face": "🥵", + "cold_face": "🥶", + "woozy_face": "🥴", + "dizzy_face": "😵", + "face_with_spiral_eyes": "😵‍💫", + "exploding_head": "🤯", + "cowboy_hat_face": "🤠", + "partying_face": "🥳", + "disguised_face": "🥸", + "sunglasses": "😎", + "nerd_face": "🤓", + "monocle_face": "🧐", + "confused": "😕", + "face_with_diagonal_mouth": "🫤", + "worried": "😟", + "slightly_frowning_face": "🙁", + "frowning_face": "☹️", + "open_mouth": "😮", + "hushed": "😯", + "astonished": "😲", + "flushed": "😳", + "pleading_face": "🥺", + "face_holding_back_tears": "🥹", + "frowning": "😦", + "anguished": "😧", + "fearful": "😨", + "cold_sweat": "😰", + "disappointed_relieved": "😥", + "cry": "😢", + "sob": "😭", + "scream": "😱", + "confounded": "😖", + "persevere": "😣", + "disappointed": "😞", + "sweat": "😓", + "weary": "😩", + "tired_face": "😫", + "yawning_face": "🥱", + "triumph": "😤", + "rage": "😡", + "pout": "😡", + "angry": "😠", + "cursing_face": "🤬", + "smiling_imp": "😈", + "imp": "👿", + "skull": "💀", + "skull_and_crossbones": "☠️", + "hankey": "💩", + "poop": "💩", + "shit": "💩", + "clown_face": "🤡", + "japanese_ogre": "👹", + "japanese_goblin": "👺", + "ghost": "👻", + "alien": "👽", + "space_invader": "👾", + "robot": "🤖", + "smiley_cat": "😺", + "smile_cat": "😸", + "joy_cat": "😹", + "heart_eyes_cat": "😻", + "smirk_cat": "😼", + "kissing_cat": "😽", + "scream_cat": "🙀", + "crying_cat_face": "😿", + "pouting_cat": "😾", + "see_no_evil": "🙈", + "hear_no_evil": "🙉", + "speak_no_evil": "🙊", + "love_letter": "💌", + "cupid": "💘", + "gift_heart": "💝", + "sparkling_heart": "💖", + "heartpulse": "💗", + "heartbeat": "💓", + "revolving_hearts": "💞", + "two_hearts": "💕", + "heart_decoration": "💟", + "heavy_heart_exclamation": "❣️", + "broken_heart": "💔", + "heart_on_fire": "❤️‍🔥", + "mending_heart": "❤️‍🩹", + "heart": "❤️", + "pink_heart": "🩷", + "orange_heart": "🧡", + "yellow_heart": "💛", + "green_heart": "💚", + "blue_heart": "💙", + "light_blue_heart": "🩵", + "purple_heart": "💜", + "brown_heart": "🤎", + "black_heart": "🖤", + "grey_heart": "🩶", + "white_heart": "🤍", + "kiss": "💋", + "anger": "💢", + "boom": "💥", + "collision": "💥", + "dizzy": "💫", + "sweat_drops": "💦", + "dash": "💨", + "hole": "🕳️", + "speech_balloon": "💬", + "eye_speech_bubble": "👁️‍🗨️", + "left_speech_bubble": "🗨️", + "right_anger_bubble": "🗯️", + "thought_balloon": "💭", + "zzz": "💤", + "wave": "👋", + "raised_back_of_hand": "🤚", + "raised_hand_with_fingers_splayed": "🖐️", + "hand": "✋", + "raised_hand": "✋", + "vulcan_salute": "🖖", + "rightwards_hand": "🫱", + "leftwards_hand": "🫲", + "palm_down_hand": "🫳", + "palm_up_hand": "🫴", + "leftwards_pushing_hand": "🫷", + "rightwards_pushing_hand": "🫸", + "ok_hand": "👌", + "pinched_fingers": "🤌", + "pinching_hand": "🤏", + "v": "✌️", + "crossed_fingers": "🤞", + "hand_with_index_finger_and_thumb_crossed": "🫰", + "love_you_gesture": "🤟", + "metal": "🤘", + "call_me_hand": "🤙", + "point_left": "👈", + "point_right": "👉", + "point_up_2": "👆", + "middle_finger": "🖕", + "fu": "🖕", + "point_down": "👇", + "point_up": "☝️", + "index_pointing_at_the_viewer": "🫵", + "+1": "👍", + "thumbsup": "👍", + "-1": "👎", + "thumbsdown": "👎", + "fist_raised": "✊", + "fist": "✊", + "fist_oncoming": "👊", + "facepunch": "👊", + "punch": "👊", + "fist_left": "🤛", + "fist_right": "🤜", + "clap": "👏", + "raised_hands": "🙌", + "heart_hands": "🫶", + "open_hands": "👐", + "palms_up_together": "🤲", + "handshake": "🤝", + "pray": "🙏", + "writing_hand": "✍️", + "nail_care": "💅", + "selfie": "🤳", + "muscle": "💪", + "mechanical_arm": "🦾", + "mechanical_leg": "🦿", + "leg": "🦵", + "foot": "🦶", + "ear": "👂", + "ear_with_hearing_aid": "🦻", + "nose": "👃", + "brain": "🧠", + "anatomical_heart": "🫀", + "lungs": "🫁", + "tooth": "🦷", + "bone": "🦴", + "eyes": "👀", + "eye": "👁️", + "tongue": "👅", + "lips": "👄", + "biting_lip": "🫦", + "baby": "👶", + "child": "🧒", + "boy": "👦", + "girl": "👧", + "adult": "🧑", + "blond_haired_person": "👱", + "man": "👨", + "bearded_person": "🧔", + "man_beard": "🧔‍♂️", + "woman_beard": "🧔‍♀️", + "red_haired_man": "👨‍🦰", + "curly_haired_man": "👨‍🦱", + "white_haired_man": "👨‍🦳", + "bald_man": "👨‍🦲", + "woman": "👩", + "red_haired_woman": "👩‍🦰", + "person_red_hair": "🧑‍🦰", + "curly_haired_woman": "👩‍🦱", + "person_curly_hair": "🧑‍🦱", + "white_haired_woman": "👩‍🦳", + "person_white_hair": "🧑‍🦳", + "bald_woman": "👩‍🦲", + "person_bald": "🧑‍🦲", + "blond_haired_woman": "👱‍♀️", + "blonde_woman": "👱‍♀️", + "blond_haired_man": "👱‍♂️", + "older_adult": "🧓", + "older_man": "👴", + "older_woman": "👵", + "frowning_person": "🙍", + "frowning_man": "🙍‍♂️", + "frowning_woman": "🙍‍♀️", + "pouting_face": "🙎", + "pouting_man": "🙎‍♂️", + "pouting_woman": "🙎‍♀️", + "no_good": "🙅", + "no_good_man": "🙅‍♂️", + "ng_man": "🙅‍♂️", + "no_good_woman": "🙅‍♀️", + "ng_woman": "🙅‍♀️", + "ok_person": "🙆", + "ok_man": "🙆‍♂️", + "ok_woman": "🙆‍♀️", + "tipping_hand_person": "💁", + "information_desk_person": "💁", + "tipping_hand_man": "💁‍♂️", + "sassy_man": "💁‍♂️", + "tipping_hand_woman": "💁‍♀️", + "sassy_woman": "💁‍♀️", + "raising_hand": "🙋", + "raising_hand_man": "🙋‍♂️", + "raising_hand_woman": "🙋‍♀️", + "deaf_person": "🧏", + "deaf_man": "🧏‍♂️", + "deaf_woman": "🧏‍♀️", + "bow": "🙇", + "bowing_man": "🙇‍♂️", + "bowing_woman": "🙇‍♀️", + "facepalm": "🤦", + "man_facepalming": "🤦‍♂️", + "woman_facepalming": "🤦‍♀️", + "shrug": "🤷", + "man_shrugging": "🤷‍♂️", + "woman_shrugging": "🤷‍♀️", + "health_worker": "🧑‍⚕️", + "man_health_worker": "👨‍⚕️", + "woman_health_worker": "👩‍⚕️", + "student": "🧑‍🎓", + "man_student": "👨‍🎓", + "woman_student": "👩‍🎓", + "teacher": "🧑‍🏫", + "man_teacher": "👨‍🏫", + "woman_teacher": "👩‍🏫", + "judge": "🧑‍⚖️", + "man_judge": "👨‍⚖️", + "woman_judge": "👩‍⚖️", + "farmer": "🧑‍🌾", + "man_farmer": "👨‍🌾", + "woman_farmer": "👩‍🌾", + "cook": "🧑‍🍳", + "man_cook": "👨‍🍳", + "woman_cook": "👩‍🍳", + "mechanic": "🧑‍🔧", + "man_mechanic": "👨‍🔧", + "woman_mechanic": "👩‍🔧", + "factory_worker": "🧑‍🏭", + "man_factory_worker": "👨‍🏭", + "woman_factory_worker": "👩‍🏭", + "office_worker": "🧑‍💼", + "man_office_worker": "👨‍💼", + "woman_office_worker": "👩‍💼", + "scientist": "🧑‍🔬", + "man_scientist": "👨‍🔬", + "woman_scientist": "👩‍🔬", + "technologist": "🧑‍💻", + "man_technologist": "👨‍💻", + "woman_technologist": "👩‍💻", + "singer": "🧑‍🎤", + "man_singer": "👨‍🎤", + "woman_singer": "👩‍🎤", + "artist": "🧑‍🎨", + "man_artist": "👨‍🎨", + "woman_artist": "👩‍🎨", + "pilot": "🧑‍✈️", + "man_pilot": "👨‍✈️", + "woman_pilot": "👩‍✈️", + "astronaut": "🧑‍🚀", + "man_astronaut": "👨‍🚀", + "woman_astronaut": "👩‍🚀", + "firefighter": "🧑‍🚒", + "man_firefighter": "👨‍🚒", + "woman_firefighter": "👩‍🚒", + "police_officer": "👮", + "cop": "👮", + "policeman": "👮‍♂️", + "policewoman": "👮‍♀️", + "detective": "🕵️", + "male_detective": "🕵️‍♂️", + "female_detective": "🕵️‍♀️", + "guard": "💂", + "guardsman": "💂‍♂️", + "guardswoman": "💂‍♀️", + "ninja": "🥷", + "construction_worker": "👷", + "construction_worker_man": "👷‍♂️", + "construction_worker_woman": "👷‍♀️", + "person_with_crown": "🫅", + "prince": "🤴", + "princess": "👸", + "person_with_turban": "👳", + "man_with_turban": "👳‍♂️", + "woman_with_turban": "👳‍♀️", + "man_with_gua_pi_mao": "👲", + "woman_with_headscarf": "🧕", + "person_in_tuxedo": "🤵", + "man_in_tuxedo": "🤵‍♂️", + "woman_in_tuxedo": "🤵‍♀️", + "person_with_veil": "👰", + "man_with_veil": "👰‍♂️", + "woman_with_veil": "👰‍♀️", + "bride_with_veil": "👰‍♀️", + "pregnant_woman": "🤰", + "pregnant_man": "🫃", + "pregnant_person": "🫄", + "breast_feeding": "🤱", + "woman_feeding_baby": "👩‍🍼", + "man_feeding_baby": "👨‍🍼", + "person_feeding_baby": "🧑‍🍼", + "angel": "👼", + "santa": "🎅", + "mrs_claus": "🤶", + "mx_claus": "🧑‍🎄", + "superhero": "🦸", + "superhero_man": "🦸‍♂️", + "superhero_woman": "🦸‍♀️", + "supervillain": "🦹", + "supervillain_man": "🦹‍♂️", + "supervillain_woman": "🦹‍♀️", + "mage": "🧙", + "mage_man": "🧙‍♂️", + "mage_woman": "🧙‍♀️", + "fairy": "🧚", + "fairy_man": "🧚‍♂️", + "fairy_woman": "🧚‍♀️", + "vampire": "🧛", + "vampire_man": "🧛‍♂️", + "vampire_woman": "🧛‍♀️", + "merperson": "🧜", + "merman": "🧜‍♂️", + "mermaid": "🧜‍♀️", + "elf": "🧝", + "elf_man": "🧝‍♂️", + "elf_woman": "🧝‍♀️", + "genie": "🧞", + "genie_man": "🧞‍♂️", + "genie_woman": "🧞‍♀️", + "zombie": "🧟", + "zombie_man": "🧟‍♂️", + "zombie_woman": "🧟‍♀️", + "troll": "🧌", + "massage": "💆", + "massage_man": "💆‍♂️", + "massage_woman": "💆‍♀️", + "haircut": "💇", + "haircut_man": "💇‍♂️", + "haircut_woman": "💇‍♀️", + "walking": "🚶", + "walking_man": "🚶‍♂️", + "walking_woman": "🚶‍♀️", + "standing_person": "🧍", + "standing_man": "🧍‍♂️", + "standing_woman": "🧍‍♀️", + "kneeling_person": "🧎", + "kneeling_man": "🧎‍♂️", + "kneeling_woman": "🧎‍♀️", + "person_with_probing_cane": "🧑‍🦯", + "man_with_probing_cane": "👨‍🦯", + "woman_with_probing_cane": "👩‍🦯", + "person_in_motorized_wheelchair": "🧑‍🦼", + "man_in_motorized_wheelchair": "👨‍🦼", + "woman_in_motorized_wheelchair": "👩‍🦼", + "person_in_manual_wheelchair": "🧑‍🦽", + "man_in_manual_wheelchair": "👨‍🦽", + "woman_in_manual_wheelchair": "👩‍🦽", + "runner": "🏃", + "running": "🏃", + "running_man": "🏃‍♂️", + "running_woman": "🏃‍♀️", + "woman_dancing": "💃", + "dancer": "💃", + "man_dancing": "🕺", + "business_suit_levitating": "🕴️", + "dancers": "👯", + "dancing_men": "👯‍♂️", + "dancing_women": "👯‍♀️", + "sauna_person": "🧖", + "sauna_man": "🧖‍♂️", + "sauna_woman": "🧖‍♀️", + "climbing": "🧗", + "climbing_man": "🧗‍♂️", + "climbing_woman": "🧗‍♀️", + "person_fencing": "🤺", + "horse_racing": "🏇", + "skier": "⛷️", + "snowboarder": "🏂", + "golfing": "🏌️", + "golfing_man": "🏌️‍♂️", + "golfing_woman": "🏌️‍♀️", + "surfer": "🏄", + "surfing_man": "🏄‍♂️", + "surfing_woman": "🏄‍♀️", + "rowboat": "🚣", + "rowing_man": "🚣‍♂️", + "rowing_woman": "🚣‍♀️", + "swimmer": "🏊", + "swimming_man": "🏊‍♂️", + "swimming_woman": "🏊‍♀️", + "bouncing_ball_person": "⛹️", + "bouncing_ball_man": "⛹️‍♂️", + "basketball_man": "⛹️‍♂️", + "bouncing_ball_woman": "⛹️‍♀️", + "basketball_woman": "⛹️‍♀️", + "weight_lifting": "🏋️", + "weight_lifting_man": "🏋️‍♂️", + "weight_lifting_woman": "🏋️‍♀️", + "bicyclist": "🚴", + "biking_man": "🚴‍♂️", + "biking_woman": "🚴‍♀️", + "mountain_bicyclist": "🚵", + "mountain_biking_man": "🚵‍♂️", + "mountain_biking_woman": "🚵‍♀️", + "cartwheeling": "🤸", + "man_cartwheeling": "🤸‍♂️", + "woman_cartwheeling": "🤸‍♀️", + "wrestling": "🤼", + "men_wrestling": "🤼‍♂️", + "women_wrestling": "🤼‍♀️", + "water_polo": "🤽", + "man_playing_water_polo": "🤽‍♂️", + "woman_playing_water_polo": "🤽‍♀️", + "handball_person": "🤾", + "man_playing_handball": "🤾‍♂️", + "woman_playing_handball": "🤾‍♀️", + "juggling_person": "🤹", + "man_juggling": "🤹‍♂️", + "woman_juggling": "🤹‍♀️", + "lotus_position": "🧘", + "lotus_position_man": "🧘‍♂️", + "lotus_position_woman": "🧘‍♀️", + "bath": "🛀", + "sleeping_bed": "🛌", + "people_holding_hands": "🧑‍🤝‍🧑", + "two_women_holding_hands": "👭", + "couple": "👫", + "two_men_holding_hands": "👬", + "couplekiss": "💏", + "couplekiss_man_woman": "👩‍❤️‍💋‍👨", + "couplekiss_man_man": "👨‍❤️‍💋‍👨", + "couplekiss_woman_woman": "👩‍❤️‍💋‍👩", + "couple_with_heart": "💑", + "couple_with_heart_woman_man": "👩‍❤️‍👨", + "couple_with_heart_man_man": "👨‍❤️‍👨", + "couple_with_heart_woman_woman": "👩‍❤️‍👩", + "family": "👪", + "family_man_woman_boy": "👨‍👩‍👦", + "family_man_woman_girl": "👨‍👩‍👧", + "family_man_woman_girl_boy": "👨‍👩‍👧‍👦", + "family_man_woman_boy_boy": "👨‍👩‍👦‍👦", + "family_man_woman_girl_girl": "👨‍👩‍👧‍👧", + "family_man_man_boy": "👨‍👨‍👦", + "family_man_man_girl": "👨‍👨‍👧", + "family_man_man_girl_boy": "👨‍👨‍👧‍👦", + "family_man_man_boy_boy": "👨‍👨‍👦‍👦", + "family_man_man_girl_girl": "👨‍👨‍👧‍👧", + "family_woman_woman_boy": "👩‍👩‍👦", + "family_woman_woman_girl": "👩‍👩‍👧", + "family_woman_woman_girl_boy": "👩‍👩‍👧‍👦", + "family_woman_woman_boy_boy": "👩‍👩‍👦‍👦", + "family_woman_woman_girl_girl": "👩‍👩‍👧‍👧", + "family_man_boy": "👨‍👦", + "family_man_boy_boy": "👨‍👦‍👦", + "family_man_girl": "👨‍👧", + "family_man_girl_boy": "👨‍👧‍👦", + "family_man_girl_girl": "👨‍👧‍👧", + "family_woman_boy": "👩‍👦", + "family_woman_boy_boy": "👩‍👦‍👦", + "family_woman_girl": "👩‍👧", + "family_woman_girl_boy": "👩‍👧‍👦", + "family_woman_girl_girl": "👩‍👧‍👧", + "speaking_head": "🗣️", + "bust_in_silhouette": "👤", + "busts_in_silhouette": "👥", + "people_hugging": "🫂", + "footprints": "👣", + "monkey_face": "🐵", + "monkey": "🐒", + "gorilla": "🦍", + "orangutan": "🦧", + "dog": "🐶", + "dog2": "🐕", + "guide_dog": "🦮", + "service_dog": "🐕‍🦺", + "poodle": "🐩", + "wolf": "🐺", + "fox_face": "🦊", + "raccoon": "🦝", + "cat": "🐱", + "cat2": "🐈", + "black_cat": "🐈‍⬛", + "lion": "🦁", + "tiger": "🐯", + "tiger2": "🐅", + "leopard": "🐆", + "horse": "🐴", + "moose": "🫎", + "donkey": "🫏", + "racehorse": "🐎", + "unicorn": "🦄", + "zebra": "🦓", + "deer": "🦌", + "bison": "🦬", + "cow": "🐮", + "ox": "🐂", + "water_buffalo": "🐃", + "cow2": "🐄", + "pig": "🐷", + "pig2": "🐖", + "boar": "🐗", + "pig_nose": "🐽", + "ram": "🐏", + "sheep": "🐑", + "goat": "🐐", + "dromedary_camel": "🐪", + "camel": "🐫", + "llama": "🦙", + "giraffe": "🦒", + "elephant": "🐘", + "mammoth": "🦣", + "rhinoceros": "🦏", + "hippopotamus": "🦛", + "mouse": "🐭", + "mouse2": "🐁", + "rat": "🐀", + "hamster": "🐹", + "rabbit": "🐰", + "rabbit2": "🐇", + "chipmunk": "🐿️", + "beaver": "🦫", + "hedgehog": "🦔", + "bat": "🦇", + "bear": "🐻", + "polar_bear": "🐻‍❄️", + "koala": "🐨", + "panda_face": "🐼", + "sloth": "🦥", + "otter": "🦦", + "skunk": "🦨", + "kangaroo": "🦘", + "badger": "🦡", + "feet": "🐾", + "paw_prints": "🐾", + "turkey": "🦃", + "chicken": "🐔", + "rooster": "🐓", + "hatching_chick": "🐣", + "baby_chick": "🐤", + "hatched_chick": "🐥", + "bird": "🐦", + "penguin": "🐧", + "dove": "🕊️", + "eagle": "🦅", + "duck": "🦆", + "swan": "🦢", + "owl": "🦉", + "dodo": "🦤", + "feather": "🪶", + "flamingo": "🦩", + "peacock": "🦚", + "parrot": "🦜", + "wing": "🪽", + "black_bird": "🐦‍⬛", + "goose": "🪿", + "frog": "🐸", + "crocodile": "🐊", + "turtle": "🐢", + "lizard": "🦎", + "snake": "🐍", + "dragon_face": "🐲", + "dragon": "🐉", + "sauropod": "🦕", + "t-rex": "🦖", + "whale": "🐳", + "whale2": "🐋", + "dolphin": "🐬", + "flipper": "🐬", + "seal": "🦭", + "fish": "🐟", + "tropical_fish": "🐠", + "blowfish": "🐡", + "shark": "🦈", + "octopus": "🐙", + "shell": "🐚", + "coral": "🪸", + "jellyfish": "🪼", + "snail": "🐌", + "butterfly": "🦋", + "bug": "🐛", + "ant": "🐜", + "bee": "🐝", + "honeybee": "🐝", + "beetle": "🪲", + "lady_beetle": "🐞", + "cricket": "🦗", + "cockroach": "🪳", + "spider": "🕷️", + "spider_web": "🕸️", + "scorpion": "🦂", + "mosquito": "🦟", + "fly": "🪰", + "worm": "🪱", + "microbe": "🦠", + "bouquet": "💐", + "cherry_blossom": "🌸", + "white_flower": "💮", + "lotus": "🪷", + "rosette": "🏵️", + "rose": "🌹", + "wilted_flower": "🥀", + "hibiscus": "🌺", + "sunflower": "🌻", + "blossom": "🌼", + "tulip": "🌷", + "hyacinth": "🪻", + "seedling": "🌱", + "potted_plant": "🪴", + "evergreen_tree": "🌲", + "deciduous_tree": "🌳", + "palm_tree": "🌴", + "cactus": "🌵", + "ear_of_rice": "🌾", + "herb": "🌿", + "shamrock": "☘️", + "four_leaf_clover": "🍀", + "maple_leaf": "🍁", + "fallen_leaf": "🍂", + "leaves": "🍃", + "empty_nest": "🪹", + "nest_with_eggs": "🪺", + "mushroom": "🍄", + "grapes": "🍇", + "melon": "🍈", + "watermelon": "🍉", + "tangerine": "🍊", + "orange": "🍊", + "mandarin": "🍊", + "lemon": "🍋", + "banana": "🍌", + "pineapple": "🍍", + "mango": "🥭", + "apple": "🍎", + "green_apple": "🍏", + "pear": "🍐", + "peach": "🍑", + "cherries": "🍒", + "strawberry": "🍓", + "blueberries": "🫐", + "kiwi_fruit": "🥝", + "tomato": "🍅", + "olive": "🫒", + "coconut": "🥥", + "avocado": "🥑", + "eggplant": "🍆", + "potato": "🥔", + "carrot": "🥕", + "corn": "🌽", + "hot_pepper": "🌶️", + "bell_pepper": "🫑", + "cucumber": "🥒", + "leafy_green": "🥬", + "broccoli": "🥦", + "garlic": "🧄", + "onion": "🧅", + "peanuts": "🥜", + "beans": "🫘", + "chestnut": "🌰", + "ginger_root": "🫚", + "pea_pod": "🫛", + "bread": "🍞", + "croissant": "🥐", + "baguette_bread": "🥖", + "flatbread": "🫓", + "pretzel": "🥨", + "bagel": "🥯", + "pancakes": "🥞", + "waffle": "🧇", + "cheese": "🧀", + "meat_on_bone": "🍖", + "poultry_leg": "🍗", + "cut_of_meat": "🥩", + "bacon": "🥓", + "hamburger": "🍔", + "fries": "🍟", + "pizza": "🍕", + "hotdog": "🌭", + "sandwich": "🥪", + "taco": "🌮", + "burrito": "🌯", + "tamale": "🫔", + "stuffed_flatbread": "🥙", + "falafel": "🧆", + "egg": "🥚", + "fried_egg": "🍳", + "shallow_pan_of_food": "🥘", + "stew": "🍲", + "fondue": "🫕", + "bowl_with_spoon": "🥣", + "green_salad": "🥗", + "popcorn": "🍿", + "butter": "🧈", + "salt": "🧂", + "canned_food": "🥫", + "bento": "🍱", + "rice_cracker": "🍘", + "rice_ball": "🍙", + "rice": "🍚", + "curry": "🍛", + "ramen": "🍜", + "spaghetti": "🍝", + "sweet_potato": "🍠", + "oden": "🍢", + "sushi": "🍣", + "fried_shrimp": "🍤", + "fish_cake": "🍥", + "moon_cake": "🥮", + "dango": "🍡", + "dumpling": "🥟", + "fortune_cookie": "🥠", + "takeout_box": "🥡", + "crab": "🦀", + "lobster": "🦞", + "shrimp": "🦐", + "squid": "🦑", + "oyster": "🦪", + "icecream": "🍦", + "shaved_ice": "🍧", + "ice_cream": "🍨", + "doughnut": "🍩", + "cookie": "🍪", + "birthday": "🎂", + "cake": "🍰", + "cupcake": "🧁", + "pie": "🥧", + "chocolate_bar": "🍫", + "candy": "🍬", + "lollipop": "🍭", + "custard": "🍮", + "honey_pot": "🍯", + "baby_bottle": "🍼", + "milk_glass": "🥛", + "coffee": "☕", + "teapot": "🫖", + "tea": "🍵", + "sake": "🍶", + "champagne": "🍾", + "wine_glass": "🍷", + "cocktail": "🍸", + "tropical_drink": "🍹", + "beer": "🍺", + "beers": "🍻", + "clinking_glasses": "🥂", + "tumbler_glass": "🥃", + "pouring_liquid": "🫗", + "cup_with_straw": "🥤", + "bubble_tea": "🧋", + "beverage_box": "🧃", + "mate": "🧉", + "ice_cube": "🧊", + "chopsticks": "🥢", + "plate_with_cutlery": "🍽️", + "fork_and_knife": "🍴", + "spoon": "🥄", + "hocho": "🔪", + "knife": "🔪", + "jar": "🫙", + "amphora": "🏺", + "earth_africa": "🌍", + "earth_americas": "🌎", + "earth_asia": "🌏", + "globe_with_meridians": "🌐", + "world_map": "🗺️", + "japan": "🗾", + "compass": "🧭", + "mountain_snow": "🏔️", + "mountain": "⛰️", + "volcano": "🌋", + "mount_fuji": "🗻", + "camping": "🏕️", + "beach_umbrella": "🏖️", + "desert": "🏜️", + "desert_island": "🏝️", + "national_park": "🏞️", + "stadium": "🏟️", + "classical_building": "🏛️", + "building_construction": "🏗️", + "bricks": "🧱", + "rock": "🪨", + "wood": "🪵", + "hut": "🛖", + "houses": "🏘️", + "derelict_house": "🏚️", + "house": "🏠", + "house_with_garden": "🏡", + "office": "🏢", + "post_office": "🏣", + "european_post_office": "🏤", + "hospital": "🏥", + "bank": "🏦", + "hotel": "🏨", + "love_hotel": "🏩", + "convenience_store": "🏪", + "school": "🏫", + "department_store": "🏬", + "factory": "🏭", + "japanese_castle": "🏯", + "european_castle": "🏰", + "wedding": "💒", + "tokyo_tower": "🗼", + "statue_of_liberty": "🗽", + "church": "⛪", + "mosque": "🕌", + "hindu_temple": "🛕", + "synagogue": "🕍", + "shinto_shrine": "⛩️", + "kaaba": "🕋", + "fountain": "⛲", + "tent": "⛺", + "foggy": "🌁", + "night_with_stars": "🌃", + "cityscape": "🏙️", + "sunrise_over_mountains": "🌄", + "sunrise": "🌅", + "city_sunset": "🌆", + "city_sunrise": "🌇", + "bridge_at_night": "🌉", + "hotsprings": "♨️", + "carousel_horse": "🎠", + "playground_slide": "🛝", + "ferris_wheel": "🎡", + "roller_coaster": "🎢", + "barber": "💈", + "circus_tent": "🎪", + "steam_locomotive": "🚂", + "railway_car": "🚃", + "bullettrain_side": "🚄", + "bullettrain_front": "🚅", + "train2": "🚆", + "metro": "🚇", + "light_rail": "🚈", + "station": "🚉", + "tram": "🚊", + "monorail": "🚝", + "mountain_railway": "🚞", + "train": "🚋", + "bus": "🚌", + "oncoming_bus": "🚍", + "trolleybus": "🚎", + "minibus": "🚐", + "ambulance": "🚑", + "fire_engine": "🚒", + "police_car": "🚓", + "oncoming_police_car": "🚔", + "taxi": "🚕", + "oncoming_taxi": "🚖", + "car": "🚗", + "red_car": "🚗", + "oncoming_automobile": "🚘", + "blue_car": "🚙", + "pickup_truck": "🛻", + "truck": "🚚", + "articulated_lorry": "🚛", + "tractor": "🚜", + "racing_car": "🏎️", + "motorcycle": "🏍️", + "motor_scooter": "🛵", + "manual_wheelchair": "🦽", + "motorized_wheelchair": "🦼", + "auto_rickshaw": "🛺", + "bike": "🚲", + "kick_scooter": "🛴", + "skateboard": "🛹", + "roller_skate": "🛼", + "busstop": "🚏", + "motorway": "🛣️", + "railway_track": "🛤️", + "oil_drum": "🛢️", + "fuelpump": "⛽", + "wheel": "🛞", + "rotating_light": "🚨", + "traffic_light": "🚥", + "vertical_traffic_light": "🚦", + "stop_sign": "🛑", + "construction": "🚧", + "anchor": "⚓", + "ring_buoy": "🛟", + "boat": "⛵", + "sailboat": "⛵", + "canoe": "🛶", + "speedboat": "🚤", + "passenger_ship": "🛳️", + "ferry": "⛴️", + "motor_boat": "🛥️", + "ship": "🚢", + "airplane": "✈️", + "small_airplane": "🛩️", + "flight_departure": "🛫", + "flight_arrival": "🛬", + "parachute": "🪂", + "seat": "💺", + "helicopter": "🚁", + "suspension_railway": "🚟", + "mountain_cableway": "🚠", + "aerial_tramway": "🚡", + "artificial_satellite": "🛰️", + "rocket": "🚀", + "flying_saucer": "🛸", + "bellhop_bell": "🛎️", + "luggage": "🧳", + "hourglass": "⌛", + "hourglass_flowing_sand": "⏳", + "watch": "⌚", + "alarm_clock": "⏰", + "stopwatch": "⏱️", + "timer_clock": "⏲️", + "mantelpiece_clock": "🕰️", + "clock12": "🕛", + "clock1230": "🕧", + "clock1": "🕐", + "clock130": "🕜", + "clock2": "🕑", + "clock230": "🕝", + "clock3": "🕒", + "clock330": "🕞", + "clock4": "🕓", + "clock430": "🕟", + "clock5": "🕔", + "clock530": "🕠", + "clock6": "🕕", + "clock630": "🕡", + "clock7": "🕖", + "clock730": "🕢", + "clock8": "🕗", + "clock830": "🕣", + "clock9": "🕘", + "clock930": "🕤", + "clock10": "🕙", + "clock1030": "🕥", + "clock11": "🕚", + "clock1130": "🕦", + "new_moon": "🌑", + "waxing_crescent_moon": "🌒", + "first_quarter_moon": "🌓", + "moon": "🌔", + "waxing_gibbous_moon": "🌔", + "full_moon": "🌕", + "waning_gibbous_moon": "🌖", + "last_quarter_moon": "🌗", + "waning_crescent_moon": "🌘", + "crescent_moon": "🌙", + "new_moon_with_face": "🌚", + "first_quarter_moon_with_face": "🌛", + "last_quarter_moon_with_face": "🌜", + "thermometer": "🌡️", + "sunny": "☀️", + "full_moon_with_face": "🌝", + "sun_with_face": "🌞", + "ringed_planet": "🪐", + "star": "⭐", + "star2": "🌟", + "stars": "🌠", + "milky_way": "🌌", + "cloud": "☁️", + "partly_sunny": "⛅", + "cloud_with_lightning_and_rain": "⛈️", + "sun_behind_small_cloud": "🌤️", + "sun_behind_large_cloud": "🌥️", + "sun_behind_rain_cloud": "🌦️", + "cloud_with_rain": "🌧️", + "cloud_with_snow": "🌨️", + "cloud_with_lightning": "🌩️", + "tornado": "🌪️", + "fog": "🌫️", + "wind_face": "🌬️", + "cyclone": "🌀", + "rainbow": "🌈", + "closed_umbrella": "🌂", + "open_umbrella": "☂️", + "umbrella": "☔", + "parasol_on_ground": "⛱️", + "zap": "⚡", + "snowflake": "❄️", + "snowman_with_snow": "☃️", + "snowman": "⛄", + "comet": "☄️", + "fire": "🔥", + "droplet": "💧", + "ocean": "🌊", + "jack_o_lantern": "🎃", + "christmas_tree": "🎄", + "fireworks": "🎆", + "sparkler": "🎇", + "firecracker": "🧨", + "sparkles": "✨", + "balloon": "🎈", + "tada": "🎉", + "confetti_ball": "🎊", + "tanabata_tree": "🎋", + "bamboo": "🎍", + "dolls": "🎎", + "flags": "🎏", + "wind_chime": "🎐", + "rice_scene": "🎑", + "red_envelope": "🧧", + "ribbon": "🎀", + "gift": "🎁", + "reminder_ribbon": "🎗️", + "tickets": "🎟️", + "ticket": "🎫", + "medal_military": "🎖️", + "trophy": "🏆", + "medal_sports": "🏅", + "1st_place_medal": "🥇", + "2nd_place_medal": "🥈", + "3rd_place_medal": "🥉", + "soccer": "⚽", + "baseball": "⚾", + "softball": "🥎", + "basketball": "🏀", + "volleyball": "🏐", + "football": "🏈", + "rugby_football": "🏉", + "tennis": "🎾", + "flying_disc": "🥏", + "bowling": "🎳", + "cricket_game": "🏏", + "field_hockey": "🏑", + "ice_hockey": "🏒", + "lacrosse": "🥍", + "ping_pong": "🏓", + "badminton": "🏸", + "boxing_glove": "🥊", + "martial_arts_uniform": "🥋", + "goal_net": "🥅", + "golf": "⛳", + "ice_skate": "⛸️", + "fishing_pole_and_fish": "🎣", + "diving_mask": "🤿", + "running_shirt_with_sash": "🎽", + "ski": "🎿", + "sled": "🛷", + "curling_stone": "🥌", + "dart": "🎯", + "yo_yo": "🪀", + "kite": "🪁", + "gun": "🔫", + "8ball": "🎱", + "crystal_ball": "🔮", + "magic_wand": "🪄", + "video_game": "🎮", + "joystick": "🕹️", + "slot_machine": "🎰", + "game_die": "🎲", + "jigsaw": "🧩", + "teddy_bear": "🧸", + "pinata": "🪅", + "mirror_ball": "🪩", + "nesting_dolls": "🪆", + "spades": "♠️", + "hearts": "♥️", + "diamonds": "♦️", + "clubs": "♣️", + "chess_pawn": "♟️", + "black_joker": "🃏", + "mahjong": "🀄", + "flower_playing_cards": "🎴", + "performing_arts": "🎭", + "framed_picture": "🖼️", + "art": "🎨", + "thread": "🧵", + "sewing_needle": "🪡", + "yarn": "🧶", + "knot": "🪢", + "eyeglasses": "👓", + "dark_sunglasses": "🕶️", + "goggles": "🥽", + "lab_coat": "🥼", + "safety_vest": "🦺", + "necktie": "👔", + "shirt": "👕", + "tshirt": "👕", + "jeans": "👖", + "scarf": "🧣", + "gloves": "🧤", + "coat": "🧥", + "socks": "🧦", + "dress": "👗", + "kimono": "👘", + "sari": "🥻", + "one_piece_swimsuit": "🩱", + "swim_brief": "🩲", + "shorts": "🩳", + "bikini": "👙", + "womans_clothes": "👚", + "folding_hand_fan": "🪭", + "purse": "👛", + "handbag": "👜", + "pouch": "👝", + "shopping": "🛍️", + "school_satchel": "🎒", + "thong_sandal": "🩴", + "mans_shoe": "👞", + "shoe": "👞", + "athletic_shoe": "👟", + "hiking_boot": "🥾", + "flat_shoe": "🥿", + "high_heel": "👠", + "sandal": "👡", + "ballet_shoes": "🩰", + "boot": "👢", + "hair_pick": "🪮", + "crown": "👑", + "womans_hat": "👒", + "tophat": "🎩", + "mortar_board": "🎓", + "billed_cap": "🧢", + "military_helmet": "🪖", + "rescue_worker_helmet": "⛑️", + "prayer_beads": "📿", + "lipstick": "💄", + "ring": "💍", + "gem": "💎", + "mute": "🔇", + "speaker": "🔈", + "sound": "🔉", + "loud_sound": "🔊", + "loudspeaker": "📢", + "mega": "📣", + "postal_horn": "📯", + "bell": "🔔", + "no_bell": "🔕", + "musical_score": "🎼", + "musical_note": "🎵", + "notes": "🎶", + "studio_microphone": "🎙️", + "level_slider": "🎚️", + "control_knobs": "🎛️", + "microphone": "🎤", + "headphones": "🎧", + "radio": "📻", + "saxophone": "🎷", + "accordion": "🪗", + "guitar": "🎸", + "musical_keyboard": "🎹", + "trumpet": "🎺", + "violin": "🎻", + "banjo": "🪕", + "drum": "🥁", + "long_drum": "🪘", + "maracas": "🪇", + "flute": "🪈", + "iphone": "📱", + "calling": "📲", + "phone": "☎️", + "telephone": "☎️", + "telephone_receiver": "📞", + "pager": "📟", + "fax": "📠", + "battery": "🔋", + "low_battery": "🪫", + "electric_plug": "🔌", + "computer": "💻", + "desktop_computer": "🖥️", + "printer": "🖨️", + "keyboard": "⌨️", + "computer_mouse": "🖱️", + "trackball": "🖲️", + "minidisc": "💽", + "floppy_disk": "💾", + "cd": "💿", + "dvd": "📀", + "abacus": "🧮", + "movie_camera": "🎥", + "film_strip": "🎞️", + "film_projector": "📽️", + "clapper": "🎬", + "tv": "📺", + "camera": "📷", + "camera_flash": "📸", + "video_camera": "📹", + "vhs": "📼", + "mag": "🔍", + "mag_right": "🔎", + "candle": "🕯️", + "bulb": "💡", + "flashlight": "🔦", + "izakaya_lantern": "🏮", + "lantern": "🏮", + "diya_lamp": "🪔", + "notebook_with_decorative_cover": "📔", + "closed_book": "📕", + "book": "📖", + "open_book": "📖", + "green_book": "📗", + "blue_book": "📘", + "orange_book": "📙", + "books": "📚", + "notebook": "📓", + "ledger": "📒", + "page_with_curl": "📃", + "scroll": "📜", + "page_facing_up": "📄", + "newspaper": "📰", + "newspaper_roll": "🗞️", + "bookmark_tabs": "📑", + "bookmark": "🔖", + "label": "🏷️", + "moneybag": "💰", + "coin": "🪙", + "yen": "💴", + "dollar": "💵", + "euro": "💶", + "pound": "💷", + "money_with_wings": "💸", + "credit_card": "💳", + "receipt": "🧾", + "chart": "💹", + "envelope": "✉️", + "email": "📧", + "e-mail": "📧", + "incoming_envelope": "📨", + "envelope_with_arrow": "📩", + "outbox_tray": "📤", + "inbox_tray": "📥", + "package": "📦", + "mailbox": "📫", + "mailbox_closed": "📪", + "mailbox_with_mail": "📬", + "mailbox_with_no_mail": "📭", + "postbox": "📮", + "ballot_box": "🗳️", + "pencil2": "✏️", + "black_nib": "✒️", + "fountain_pen": "🖋️", + "pen": "🖊️", + "paintbrush": "🖌️", + "crayon": "🖍️", + "memo": "📝", + "pencil": "📝", + "briefcase": "💼", + "file_folder": "📁", + "open_file_folder": "📂", + "card_index_dividers": "🗂️", + "date": "📅", + "calendar": "📆", + "spiral_notepad": "🗒️", + "spiral_calendar": "🗓️", + "card_index": "📇", + "chart_with_upwards_trend": "📈", + "chart_with_downwards_trend": "📉", + "bar_chart": "📊", + "clipboard": "📋", + "pushpin": "📌", + "round_pushpin": "📍", + "paperclip": "📎", + "paperclips": "🖇️", + "straight_ruler": "📏", + "triangular_ruler": "📐", + "scissors": "✂️", + "card_file_box": "🗃️", + "file_cabinet": "🗄️", + "wastebasket": "🗑️", + "lock": "🔒", + "unlock": "🔓", + "lock_with_ink_pen": "🔏", + "closed_lock_with_key": "🔐", + "key": "🔑", + "old_key": "🗝️", + "hammer": "🔨", + "axe": "🪓", + "pick": "⛏️", + "hammer_and_pick": "⚒️", + "hammer_and_wrench": "🛠️", + "dagger": "🗡️", + "crossed_swords": "⚔️", + "bomb": "💣", + "boomerang": "🪃", + "bow_and_arrow": "🏹", + "shield": "🛡️", + "carpentry_saw": "🪚", + "wrench": "🔧", + "screwdriver": "🪛", + "nut_and_bolt": "🔩", + "gear": "⚙️", + "clamp": "🗜️", + "balance_scale": "⚖️", + "probing_cane": "🦯", + "link": "🔗", + "chains": "⛓️", + "hook": "🪝", + "toolbox": "🧰", + "magnet": "🧲", + "ladder": "🪜", + "alembic": "⚗️", + "test_tube": "🧪", + "petri_dish": "🧫", + "dna": "🧬", + "microscope": "🔬", + "telescope": "🔭", + "satellite": "📡", + "syringe": "💉", + "drop_of_blood": "🩸", + "pill": "💊", + "adhesive_bandage": "🩹", + "crutch": "🩼", + "stethoscope": "🩺", + "x_ray": "🩻", + "door": "🚪", + "elevator": "🛗", + "mirror": "🪞", + "window": "🪟", + "bed": "🛏️", + "couch_and_lamp": "🛋️", + "chair": "🪑", + "toilet": "🚽", + "plunger": "🪠", + "shower": "🚿", + "bathtub": "🛁", + "mouse_trap": "🪤", + "razor": "🪒", + "lotion_bottle": "🧴", + "safety_pin": "🧷", + "broom": "🧹", + "basket": "🧺", + "roll_of_paper": "🧻", + "bucket": "🪣", + "soap": "🧼", + "bubbles": "🫧", + "toothbrush": "🪥", + "sponge": "🧽", + "fire_extinguisher": "🧯", + "shopping_cart": "🛒", + "smoking": "🚬", + "coffin": "⚰️", + "headstone": "🪦", + "funeral_urn": "⚱️", + "nazar_amulet": "🧿", + "hamsa": "🪬", + "moyai": "🗿", + "placard": "🪧", + "identification_card": "🪪", + "atm": "🏧", + "put_litter_in_its_place": "🚮", + "potable_water": "🚰", + "wheelchair": "♿", + "mens": "🚹", + "womens": "🚺", + "restroom": "🚻", + "baby_symbol": "🚼", + "wc": "🚾", + "passport_control": "🛂", + "customs": "🛃", + "baggage_claim": "🛄", + "left_luggage": "🛅", + "warning": "⚠️", + "children_crossing": "🚸", + "no_entry": "⛔", + "no_entry_sign": "🚫", + "no_bicycles": "🚳", + "no_smoking": "🚭", + "do_not_litter": "🚯", + "non-potable_water": "🚱", + "no_pedestrians": "🚷", + "no_mobile_phones": "📵", + "underage": "🔞", + "radioactive": "☢️", + "biohazard": "☣️", + "arrow_up": "⬆️", + "arrow_upper_right": "↗️", + "arrow_right": "➡️", + "arrow_lower_right": "↘️", + "arrow_down": "⬇️", + "arrow_lower_left": "↙️", + "arrow_left": "⬅️", + "arrow_upper_left": "↖️", + "arrow_up_down": "↕️", + "left_right_arrow": "↔️", + "leftwards_arrow_with_hook": "↩️", + "arrow_right_hook": "↪️", + "arrow_heading_up": "⤴️", + "arrow_heading_down": "⤵️", + "arrows_clockwise": "🔃", + "arrows_counterclockwise": "🔄", + "back": "🔙", + "end": "🔚", + "on": "🔛", + "soon": "🔜", + "top": "🔝", + "place_of_worship": "🛐", + "atom_symbol": "⚛️", + "om": "🕉️", + "star_of_david": "✡️", + "wheel_of_dharma": "☸️", + "yin_yang": "☯️", + "latin_cross": "✝️", + "orthodox_cross": "☦️", + "star_and_crescent": "☪️", + "peace_symbol": "☮️", + "menorah": "🕎", + "six_pointed_star": "🔯", + "khanda": "🪯", + "aries": "♈", + "taurus": "♉", + "gemini": "♊", + "cancer": "♋", + "leo": "♌", + "virgo": "♍", + "libra": "♎", + "scorpius": "♏", + "sagittarius": "♐", + "capricorn": "♑", + "aquarius": "♒", + "pisces": "♓", + "ophiuchus": "⛎", + "twisted_rightwards_arrows": "🔀", + "repeat": "🔁", + "repeat_one": "🔂", + "arrow_forward": "▶️", + "fast_forward": "⏩", + "next_track_button": "⏭️", + "play_or_pause_button": "⏯️", + "arrow_backward": "◀️", + "rewind": "⏪", + "previous_track_button": "⏮️", + "arrow_up_small": "🔼", + "arrow_double_up": "⏫", + "arrow_down_small": "🔽", + "arrow_double_down": "⏬", + "pause_button": "⏸️", + "stop_button": "⏹️", + "record_button": "⏺️", + "eject_button": "⏏️", + "cinema": "🎦", + "low_brightness": "🔅", + "high_brightness": "🔆", + "signal_strength": "📶", + "wireless": "🛜", + "vibration_mode": "📳", + "mobile_phone_off": "📴", + "female_sign": "♀️", + "male_sign": "♂️", + "transgender_symbol": "⚧️", + "heavy_multiplication_x": "✖️", + "heavy_plus_sign": "➕", + "heavy_minus_sign": "➖", + "heavy_division_sign": "➗", + "heavy_equals_sign": "🟰", + "infinity": "♾️", + "bangbang": "‼️", + "interrobang": "⁉️", + "question": "❓", + "grey_question": "❔", + "grey_exclamation": "❕", + "exclamation": "❗", + "heavy_exclamation_mark": "❗", + "wavy_dash": "〰️", + "currency_exchange": "💱", + "heavy_dollar_sign": "💲", + "medical_symbol": "⚕️", + "recycle": "♻️", + "fleur_de_lis": "⚜️", + "trident": "🔱", + "name_badge": "📛", + "beginner": "🔰", + "o": "⭕", + "white_check_mark": "✅", + "ballot_box_with_check": "☑️", + "heavy_check_mark": "✔️", + "x": "❌", + "negative_squared_cross_mark": "❎", + "curly_loop": "➰", + "loop": "➿", + "part_alternation_mark": "〽️", + "eight_spoked_asterisk": "✳️", + "eight_pointed_black_star": "✴️", + "sparkle": "❇️", + "copyright": "©️", + "registered": "®️", + "tm": "™️", + "hash": "#️⃣", + "asterisk": "*️⃣", + "zero": "0️⃣", + "one": "1️⃣", + "two": "2️⃣", + "three": "3️⃣", + "four": "4️⃣", + "five": "5️⃣", + "six": "6️⃣", + "seven": "7️⃣", + "eight": "8️⃣", + "nine": "9️⃣", + "keycap_ten": "🔟", + "capital_abcd": "🔠", + "abcd": "🔡", + "symbols": "🔣", + "abc": "🔤", + "a": "🅰️", + "ab": "🆎", + "b": "🅱️", + "cl": "🆑", + "cool": "🆒", + "free": "🆓", + "information_source": "ℹ️", + "id": "🆔", + "m": "Ⓜ️", + "new": "🆕", + "ng": "🆖", + "o2": "🅾️", + "ok": "🆗", + "parking": "🅿️", + "sos": "🆘", + "up": "🆙", + "vs": "🆚", + "koko": "🈁", + "sa": "🈂️", + "ideograph_advantage": "🉐", + "accept": "🉑", + "congratulations": "㊗️", + "secret": "㊙️", + "u6e80": "🈵", + "red_circle": "🔴", + "orange_circle": "🟠", + "yellow_circle": "🟡", + "green_circle": "🟢", + "large_blue_circle": "🔵", + "purple_circle": "🟣", + "brown_circle": "🟤", + "black_circle": "⚫", + "white_circle": "⚪", + "red_square": "🟥", + "orange_square": "🟧", + "yellow_square": "🟨", + "green_square": "🟩", + "blue_square": "🟦", + "purple_square": "🟪", + "brown_square": "🟫", + "black_large_square": "⬛", + "white_large_square": "⬜", + "black_medium_square": "◼️", + "white_medium_square": "◻️", + "black_medium_small_square": "◾", + "white_medium_small_square": "◽", + "black_small_square": "▪️", + "white_small_square": "▫️", + "large_orange_diamond": "🔶", + "large_blue_diamond": "🔷", + "small_orange_diamond": "🔸", + "small_blue_diamond": "🔹", + "small_red_triangle": "🔺", + "small_red_triangle_down": "🔻", + "diamond_shape_with_a_dot_inside": "💠", + "radio_button": "🔘", + "white_square_button": "🔳", + "black_square_button": "🔲", + "checkered_flag": "🏁", + "triangular_flag_on_post": "🚩", + "crossed_flags": "🎌", + "black_flag": "🏴", + "white_flag": "🏳️", + "rainbow_flag": "🏳️‍🌈", + "transgender_flag": "🏳️‍⚧️", + "pirate_flag": "🏴‍☠️", + "ascension_island": "🇦🇨", + "andorra": "🇦🇩", + "united_arab_emirates": "🇦🇪", + "afghanistan": "🇦🇫", + "antigua_barbuda": "🇦🇬", + "anguilla": "🇦🇮", + "albania": "🇦🇱", + "armenia": "🇦🇲", + "angola": "🇦🇴", + "antarctica": "🇦🇶", + "argentina": "🇦🇷", + "american_samoa": "🇦🇸", + "austria": "🇦🇹", + "australia": "🇦🇺", + "aruba": "🇦🇼", + "aland_islands": "🇦🇽", + "azerbaijan": "🇦🇿", + "bosnia_herzegovina": "🇧🇦", + "barbados": "🇧🇧", + "bangladesh": "🇧🇩", + "belgium": "🇧🇪", + "burkina_faso": "🇧🇫", + "bulgaria": "🇧🇬", + "bahrain": "🇧🇭", + "burundi": "🇧🇮", + "benin": "🇧🇯", + "st_barthelemy": "🇧🇱", + "bermuda": "🇧🇲", + "brunei": "🇧🇳", + "bolivia": "🇧🇴", + "caribbean_netherlands": "🇧🇶", + "brazil": "🇧🇷", + "bahamas": "🇧🇸", + "bhutan": "🇧🇹", + "bouvet_island": "🇧🇻", + "botswana": "🇧🇼", + "belarus": "🇧🇾", + "belize": "🇧🇿", + "canada": "🇨🇦", + "cocos_islands": "🇨🇨", + "congo_kinshasa": "🇨🇩", + "central_african_republic": "🇨🇫", + "congo_brazzaville": "🇨🇬", + "switzerland": "🇨🇭", + "cote_divoire": "🇨🇮", + "cook_islands": "🇨🇰", + "chile": "🇨🇱", + "cameroon": "🇨🇲", + "cn": "🇨🇳", + "colombia": "🇨🇴", + "clipperton_island": "🇨🇵", + "costa_rica": "🇨🇷", + "cuba": "🇨🇺", + "cape_verde": "🇨🇻", + "curacao": "🇨🇼", + "christmas_island": "🇨🇽", + "cyprus": "🇨🇾", + "czech_republic": "🇨🇿", + "de": "🇩🇪", + "diego_garcia": "🇩🇬", + "djibouti": "🇩🇯", + "denmark": "🇩🇰", + "dominica": "🇩🇲", + "dominican_republic": "🇩🇴", + "algeria": "🇩🇿", + "ceuta_melilla": "🇪🇦", + "ecuador": "🇪🇨", + "estonia": "🇪🇪", + "egypt": "🇪🇬", + "western_sahara": "🇪🇭", + "eritrea": "🇪🇷", + "es": "🇪🇸", + "ethiopia": "🇪🇹", + "eu": "🇪🇺", + "european_union": "🇪🇺", + "finland": "🇫🇮", + "fiji": "🇫🇯", + "falkland_islands": "🇫🇰", + "micronesia": "🇫🇲", + "faroe_islands": "🇫🇴", + "fr": "🇫🇷", + "gabon": "🇬🇦", + "gb": "🇬🇧", + "uk": "🇬🇧", + "grenada": "🇬🇩", + "georgia": "🇬🇪", + "french_guiana": "🇬🇫", + "guernsey": "🇬🇬", + "ghana": "🇬🇭", + "gibraltar": "🇬🇮", + "greenland": "🇬🇱", + "gambia": "🇬🇲", + "guinea": "🇬🇳", + "guadeloupe": "🇬🇵", + "equatorial_guinea": "🇬🇶", + "greece": "🇬🇷", + "south_georgia_south_sandwich_islands": "🇬🇸", + "guatemala": "🇬🇹", + "guam": "🇬🇺", + "guinea_bissau": "🇬🇼", + "guyana": "🇬🇾", + "hong_kong": "🇭🇰", + "heard_mcdonald_islands": "🇭🇲", + "honduras": "🇭🇳", + "croatia": "🇭🇷", + "haiti": "🇭🇹", + "hungary": "🇭🇺", + "canary_islands": "🇮🇨", + "indonesia": "🇮🇩", + "ireland": "🇮🇪", + "israel": "🇮🇱", + "isle_of_man": "🇮🇲", + "india": "🇮🇳", + "british_indian_ocean_territory": "🇮🇴", + "iraq": "🇮🇶", + "iran": "🇮🇷", + "iceland": "🇮🇸", + "it": "🇮🇹", + "jersey": "🇯🇪", + "jamaica": "🇯🇲", + "jordan": "🇯🇴", + "jp": "🇯🇵", + "kenya": "🇰🇪", + "kyrgyzstan": "🇰🇬", + "cambodia": "🇰🇭", + "kiribati": "🇰🇮", + "comoros": "🇰🇲", + "st_kitts_nevis": "🇰🇳", + "north_korea": "🇰🇵", + "kr": "🇰🇷", + "kuwait": "🇰🇼", + "cayman_islands": "🇰🇾", + "kazakhstan": "🇰🇿", + "laos": "🇱🇦", + "lebanon": "🇱🇧", + "st_lucia": "🇱🇨", + "liechtenstein": "🇱🇮", + "sri_lanka": "🇱🇰", + "liberia": "🇱🇷", + "lesotho": "🇱🇸", + "lithuania": "🇱🇹", + "luxembourg": "🇱🇺", + "latvia": "🇱🇻", + "libya": "🇱🇾", + "morocco": "🇲🇦", + "monaco": "🇲🇨", + "moldova": "🇲🇩", + "montenegro": "🇲🇪", + "st_martin": "🇲🇫", + "madagascar": "🇲🇬", + "marshall_islands": "🇲🇭", + "macedonia": "🇲🇰", + "mali": "🇲🇱", + "myanmar": "🇲🇲", + "mongolia": "🇲🇳", + "macau": "🇲🇴", + "northern_mariana_islands": "🇲🇵", + "martinique": "🇲🇶", + "mauritania": "🇲🇷", + "montserrat": "🇲🇸", + "malta": "🇲🇹", + "mauritius": "🇲🇺", + "maldives": "🇲🇻", + "malawi": "🇲🇼", + "mexico": "🇲🇽", + "malaysia": "🇲🇾", + "mozambique": "🇲🇿", + "namibia": "🇳🇦", + "new_caledonia": "🇳🇨", + "niger": "🇳🇪", + "norfolk_island": "🇳🇫", + "nigeria": "🇳🇬", + "nicaragua": "🇳🇮", + "netherlands": "🇳🇱", + "norway": "🇳🇴", + "nepal": "🇳🇵", + "nauru": "🇳🇷", + "niue": "🇳🇺", + "new_zealand": "🇳🇿", + "oman": "🇴🇲", + "panama": "🇵🇦", + "peru": "🇵🇪", + "french_polynesia": "🇵🇫", + "papua_new_guinea": "🇵🇬", + "philippines": "🇵🇭", + "pakistan": "🇵🇰", + "poland": "🇵🇱", + "st_pierre_miquelon": "🇵🇲", + "pitcairn_islands": "🇵🇳", + "puerto_rico": "🇵🇷", + "palestinian_territories": "🇵🇸", + "portugal": "🇵🇹", + "palau": "🇵🇼", + "paraguay": "🇵🇾", + "qatar": "🇶🇦", + "reunion": "🇷🇪", + "romania": "🇷🇴", + "serbia": "🇷🇸", + "ru": "🇷🇺", + "rwanda": "🇷🇼", + "saudi_arabia": "🇸🇦", + "solomon_islands": "🇸🇧", + "seychelles": "🇸🇨", + "sudan": "🇸🇩", + "sweden": "🇸🇪", + "singapore": "🇸🇬", + "st_helena": "🇸🇭", + "slovenia": "🇸🇮", + "svalbard_jan_mayen": "🇸🇯", + "slovakia": "🇸🇰", + "sierra_leone": "🇸🇱", + "san_marino": "🇸🇲", + "senegal": "🇸🇳", + "somalia": "🇸🇴", + "suriname": "🇸🇷", + "south_sudan": "🇸🇸", + "sao_tome_principe": "🇸🇹", + "el_salvador": "🇸🇻", + "sint_maarten": "🇸🇽", + "syria": "🇸🇾", + "swaziland": "🇸🇿", + "tristan_da_cunha": "🇹🇦", + "turks_caicos_islands": "🇹🇨", + "chad": "🇹🇩", + "french_southern_territories": "🇹🇫", + "togo": "🇹🇬", + "thailand": "🇹🇭", + "tajikistan": "🇹🇯", + "tokelau": "🇹🇰", + "timor_leste": "🇹🇱", + "turkmenistan": "🇹🇲", + "tunisia": "🇹🇳", + "tonga": "🇹🇴", + "tr": "🇹🇷", + "trinidad_tobago": "🇹🇹", + "tuvalu": "🇹🇻", + "taiwan": "🇹🇼", + "tanzania": "🇹🇿", + "ukraine": "🇺🇦", + "uganda": "🇺🇬", + "us_outlying_islands": "🇺🇲", + "united_nations": "🇺🇳", + "us": "🇺🇸", + "uruguay": "🇺🇾", + "uzbekistan": "🇺🇿", + "vatican_city": "🇻🇦", + "st_vincent_grenadines": "🇻🇨", + "venezuela": "🇻🇪", + "british_virgin_islands": "🇻🇬", + "us_virgin_islands": "🇻🇮", + "vietnam": "🇻🇳", + "vanuatu": "🇻🇺", + "wallis_futuna": "🇼🇫", + "samoa": "🇼🇸", + "kosovo": "🇽🇰", + "yemen": "🇾🇪", + "mayotte": "🇾🇹", + "south_africa": "🇿🇦", + "zambia": "🇿🇲", + "zimbabwe": "🇿🇼", + "england": "🏴󠁧󠁢󠁥󠁮󠁧󠁿", + "scotland": "🏴󠁧󠁢󠁳󠁣󠁴󠁿", + "wales": "🏴󠁧󠁢󠁷󠁬󠁳󠁿" +}; + + +export interface EmojiShortcuts { + [key: string]: string | string[]; +} + +const shortcuts: EmojiShortcuts = { + angry: ['>:(', '>:-('], + blush: [':")', ':-")'], + broken_heart: [' tags -// -import MarkdownIt, {StateBlock, StateCore, Token} from 'markdown-it'; - -/** - * 环境接口,包含缩写定义 - */ -interface AbbrEnv { - abbreviations?: { [key: string]: string }; -} - -/** - * markdown-it-abbr 插件 - * 用于支持缩写语法 - */ -export default function abbr_plugin(md: MarkdownIt): void { - const escapeRE = md.utils.escapeRE; - const arrayReplaceAt = md.utils.arrayReplaceAt; - - // ASCII characters in Cc, Sc, Sm, Sk categories we should terminate on; - // you can check character classes here: - // http://www.unicode.org/Public/UNIDATA/UnicodeData.txt - const OTHER_CHARS = ' \r\n$+<=>^`|~'; - - const UNICODE_PUNCT_RE = md.utils.lib.ucmicro.P.source; - const UNICODE_SPACE_RE = md.utils.lib.ucmicro.Z.source; - - function abbr_def(state: StateBlock, startLine: number, endLine: number, silent: boolean): boolean { - let labelEnd: number; - let pos = state.bMarks[startLine] + state.tShift[startLine]; - const max = state.eMarks[startLine]; - - if (pos + 2 >= max) { return false; } - - if (state.src.charCodeAt(pos++) !== 0x2A/* * */) { return false; } - if (state.src.charCodeAt(pos++) !== 0x5B/* [ */) { return false; } - - const labelStart = pos; - - for (; pos < max; pos++) { - const ch = state.src.charCodeAt(pos); - if (ch === 0x5B /* [ */) { - return false; - } else if (ch === 0x5D /* ] */) { - labelEnd = pos; - break; - } else if (ch === 0x5C /* \ */) { - pos++; - } - } - - if (labelEnd! < 0 || state.src.charCodeAt(labelEnd! + 1) !== 0x3A/* : */) { - return false; - } - - if (silent) { return true; } - - const label = state.src.slice(labelStart, labelEnd!).replace(/\\(.)/g, '$1'); - const title = state.src.slice(labelEnd! + 2, max).trim(); - if (label.length === 0) { return false; } - if (title.length === 0) { return false; } - - const env = state.env as AbbrEnv; - if (!env.abbreviations) { env.abbreviations = {}; } - // prepend ':' to avoid conflict with Object.prototype members - if (typeof env.abbreviations[':' + label] === 'undefined') { - env.abbreviations[':' + label] = title; - } - - state.line = startLine + 1; - return true; - } - - function abbr_replace(state: StateCore): void { - const blockTokens = state.tokens; - - const env = state.env as AbbrEnv; - if (!env.abbreviations) { return; } - - const regSimple = new RegExp('(?:' + - Object.keys(env.abbreviations).map(function (x: string) { - return x.substr(1); - }).sort(function (a: string, b: string) { - return b.length - a.length; - }).map(escapeRE).join('|') + - ')'); - - const regText = '(^|' + UNICODE_PUNCT_RE + '|' + UNICODE_SPACE_RE + - '|[' + OTHER_CHARS.split('').map(escapeRE).join('') + '])' + - '(' + Object.keys(env.abbreviations).map(function (x: string) { - return x.substr(1); - }).sort(function (a: string, b: string) { - return b.length - a.length; - }).map(escapeRE).join('|') + ')' + - '($|' + UNICODE_PUNCT_RE + '|' + UNICODE_SPACE_RE + - '|[' + OTHER_CHARS.split('').map(escapeRE).join('') + '])' - - const reg = new RegExp(regText, 'g'); - - for (let j = 0, l = blockTokens.length; j < l; j++) { - if (blockTokens[j].type !== 'inline') { continue; } - let tokens = blockTokens[j].children!; - - // We scan from the end, to keep position when new tags added. - for (let i = tokens.length - 1; i >= 0; i--) { - const currentToken = tokens[i]; - if (currentToken.type !== 'text') { continue; } - - let pos = 0; - const text = currentToken.content; - reg.lastIndex = 0; - const nodes: Token[] = []; - - // fast regexp run to determine whether there are any abbreviated words - // in the current token - if (!regSimple.test(text)) { continue; } - - let m: RegExpExecArray | null; - - while ((m = reg.exec(text))) { - if (m.index > 0 || m[1].length > 0) { - const token = new state.Token('text', '', 0); - token.content = text.slice(pos, m.index + m[1].length); - nodes.push(token); - } - - const token_o = new state.Token('abbr_open', 'abbr', 1); - token_o.attrs = [['title', env.abbreviations[':' + m[2]]]]; - nodes.push(token_o); - - const token_t = new state.Token('text', '', 0); - token_t.content = m[2]; - nodes.push(token_t); - - const token_c = new state.Token('abbr_close', 'abbr', -1); - nodes.push(token_c); - - reg.lastIndex -= m[3].length; - pos = reg.lastIndex; - } - - if (!nodes.length) { continue; } - - if (pos < text.length) { - const token = new state.Token('text', '', 0); - token.content = text.slice(pos); - nodes.push(token); - } - - // replace current node - blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes); - } - } - } - - md.block.ruler.before('reference', 'abbr_def', abbr_def, { alt: ['paragraph', 'reference'] }); - - md.core.ruler.after('linkify', 'abbr_replace', abbr_replace); -} \ No newline at end of file diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-deflist/index.ts b/frontend/src/common/markdown-it/plugins/markdown-it-deflist/index.ts deleted file mode 100644 index 925679d..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-deflist/index.ts +++ /dev/null @@ -1,209 +0,0 @@ -// Process definition lists -// -import MarkdownIt, { StateBlock, Token } from 'markdown-it'; - -/** - * markdown-it-deflist 插件 - * 用于支持定义列表语法 - */ -export default function deflist_plugin(md: MarkdownIt): void { - const isSpace = md.utils.isSpace; - - // Search `[:~][\n ]`, returns next pos after marker on success - // or -1 on fail. - function skipMarker(state: StateBlock, line: number): number { - let start = state.bMarks[line] + state.tShift[line]; - const max = state.eMarks[line]; - - if (start >= max) { return -1; } - - // Check bullet - const marker = state.src.charCodeAt(start++); - if (marker !== 0x7E/* ~ */ && marker !== 0x3A/* : */) { return -1; } - - const pos = state.skipSpaces(start); - - // require space after ":" - if (start === pos) { return -1; } - - // no empty definitions, e.g. " : " - if (pos >= max) { return -1; } - - return start; - } - - function markTightParagraphs(state: StateBlock, idx: number): void { - const level = state.level + 2; - - for (let i = idx + 2, l = state.tokens.length - 2; i < l; i++) { - if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') { - state.tokens[i + 2].hidden = true; - state.tokens[i].hidden = true; - i += 2; - } - } - } - - function deflist(state: StateBlock, startLine: number, endLine: number, silent: boolean): boolean { - if (silent) { - // quirk: validation mode validates a dd block only, not a whole deflist - if (state.ddIndent < 0) { return false; } - return skipMarker(state, startLine) >= 0; - } - - let nextLine = startLine + 1; - if (nextLine >= endLine) { return false; } - - if (state.isEmpty(nextLine)) { - nextLine++; - if (nextLine >= endLine) { return false; } - } - - if (state.sCount[nextLine] < state.blkIndent) { return false; } - let contentStart = skipMarker(state, nextLine); - if (contentStart < 0) { return false; } - - // Start list - const listTokIdx = state.tokens.length; - let tight = true; - - const token_dl_o: Token = state.push('dl_open', 'dl', 1); - const listLines: [number, number] = [startLine, 0]; - token_dl_o.map = listLines; - - // - // Iterate list items - // - - let dtLine = startLine; - let ddLine = nextLine; - - // One definition list can contain multiple DTs, - // and one DT can be followed by multiple DDs. - // - // Thus, there is two loops here, and label is - // needed to break out of the second one - // - /* eslint no-labels:0,block-scoped-var:0 */ - OUTER: - for (;;) { - let prevEmptyEnd = false; - - const token_dt_o: Token = state.push('dt_open', 'dt', 1); - token_dt_o.map = [dtLine, dtLine]; - - const token_i: Token = state.push('inline', '', 0); - token_i.map = [dtLine, dtLine]; - token_i.content = state.getLines(dtLine, dtLine + 1, state.blkIndent, false).trim(); - token_i.children = []; - - state.push('dt_close', 'dt', -1); - - for (;;) { - const token_dd_o: Token = state.push('dd_open', 'dd', 1); - const itemLines: [number, number] = [nextLine, 0]; - token_dd_o.map = itemLines; - - let pos = contentStart; - const max = state.eMarks[ddLine]; - let offset = state.sCount[ddLine] + contentStart - (state.bMarks[ddLine] + state.tShift[ddLine]); - - while (pos < max) { - const ch = state.src.charCodeAt(pos); - - if (isSpace(ch)) { - if (ch === 0x09) { - offset += 4 - offset % 4; - } else { - offset++; - } - } else { - break; - } - - pos++; - } - - contentStart = pos; - - const oldTight = state.tight; - const oldDDIndent = state.ddIndent; - const oldIndent = state.blkIndent; - const oldTShift = state.tShift[ddLine]; - const oldSCount = state.sCount[ddLine]; - const oldParentType = state.parentType; - state.blkIndent = state.ddIndent = state.sCount[ddLine] + 2; - state.tShift[ddLine] = contentStart - state.bMarks[ddLine]; - state.sCount[ddLine] = offset; - state.tight = true; - state.parentType = 'deflist' as any; - - state.md.block.tokenize(state, ddLine, endLine); - - // If any of list item is tight, mark list as tight - if (!state.tight || prevEmptyEnd) { - tight = false; - } - // Item become loose if finish with empty line, - // but we should filter last element, because it means list finish - prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1); - - state.tShift[ddLine] = oldTShift; - state.sCount[ddLine] = oldSCount; - state.tight = oldTight; - state.parentType = oldParentType; - state.blkIndent = oldIndent; - state.ddIndent = oldDDIndent; - - state.push('dd_close', 'dd', -1); - - itemLines[1] = nextLine = state.line; - - if (nextLine >= endLine) { break OUTER; } - - if (state.sCount[nextLine] < state.blkIndent) { break OUTER; } - contentStart = skipMarker(state, nextLine); - if (contentStart < 0) { break; } - - ddLine = nextLine; - - // go to the next loop iteration: - // insert DD tag and repeat checking - } - - if (nextLine >= endLine) { break; } - dtLine = nextLine; - - if (state.isEmpty(dtLine)) { break; } - if (state.sCount[dtLine] < state.blkIndent) { break; } - - ddLine = dtLine + 1; - if (ddLine >= endLine) { break; } - if (state.isEmpty(ddLine)) { ddLine++; } - if (ddLine >= endLine) { break; } - - if (state.sCount[ddLine] < state.blkIndent) { break; } - contentStart = skipMarker(state, ddLine); - if (contentStart < 0) { break; } - - // go to the next loop iteration: - // insert DT and DD tags and repeat checking - } - - // Finilize list - state.push('dl_close', 'dl', -1); - - listLines[1] = nextLine; - - state.line = nextLine; - - // mark paragraphs tight if needed - if (tight) { - markTightParagraphs(state, listTokIdx); - } - - return true; - } - - md.block.ruler.before('paragraph', 'deflist', deflist, { alt: ['paragraph', 'reference', 'blockquote'] }); -} \ No newline at end of file diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/index.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/index.ts deleted file mode 100644 index ca69b59..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { default as bare } from './lib/bare'; -export { default as light } from './lib/light'; -export { default as full } from './lib/full'; - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/bare.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/bare.ts deleted file mode 100644 index 2d7669f..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/bare.ts +++ /dev/null @@ -1,26 +0,0 @@ -import MarkdownIt from 'markdown-it'; -import emoji_html from './render'; -import emoji_replace from './replace'; -import normalize_opts, { EmojiOptions } from './normalize_opts'; - -/** - * Bare emoji 插件(不包含预定义的 emoji 数据) - */ -export default function emoji_plugin(md: MarkdownIt, options?: Partial): void { - const defaults: EmojiOptions = { - defs: {}, - shortcuts: {}, - enabled: [] - }; - - const opts = normalize_opts(md.utils.assign({}, defaults, options || {}) as EmojiOptions); - - md.renderer.rules.emoji = emoji_html; - - md.core.ruler.after( - 'linkify', - 'emoji', - emoji_replace(md, opts.defs, opts.shortcuts, opts.scanRE, opts.replaceRE) - ); -} - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/full.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/full.ts deleted file mode 100644 index 6e6a097..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/full.ts +++ /dev/null @@ -1,1910 +0,0 @@ -// Generated, don't edit -import { EmojiDefs } from '../normalize_opts'; - -const emojies: EmojiDefs = { - "100": "💯", - "1234": "🔢", - "grinning": "😀", - "smiley": "😃", - "smile": "😄", - "grin": "😁", - "laughing": "😆", - "satisfied": "😆", - "sweat_smile": "😅", - "rofl": "🤣", - "joy": "😂", - "slightly_smiling_face": "🙂", - "upside_down_face": "🙃", - "melting_face": "🫠", - "wink": "😉", - "blush": "😊", - "innocent": "😇", - "smiling_face_with_three_hearts": "🥰", - "heart_eyes": "😍", - "star_struck": "🤩", - "kissing_heart": "😘", - "kissing": "😗", - "relaxed": "☺️", - "kissing_closed_eyes": "😚", - "kissing_smiling_eyes": "😙", - "smiling_face_with_tear": "🥲", - "yum": "😋", - "stuck_out_tongue": "😛", - "stuck_out_tongue_winking_eye": "😜", - "zany_face": "🤪", - "stuck_out_tongue_closed_eyes": "😝", - "money_mouth_face": "🤑", - "hugs": "🤗", - "hand_over_mouth": "🤭", - "face_with_open_eyes_and_hand_over_mouth": "🫢", - "face_with_peeking_eye": "🫣", - "shushing_face": "🤫", - "thinking": "🤔", - "saluting_face": "🫡", - "zipper_mouth_face": "🤐", - "raised_eyebrow": "🤨", - "neutral_face": "😐", - "expressionless": "😑", - "no_mouth": "😶", - "dotted_line_face": "🫥", - "face_in_clouds": "😶‍🌫️", - "smirk": "😏", - "unamused": "😒", - "roll_eyes": "🙄", - "grimacing": "😬", - "face_exhaling": "😮‍💨", - "lying_face": "🤥", - "shaking_face": "🫨", - "relieved": "😌", - "pensive": "😔", - "sleepy": "😪", - "drooling_face": "🤤", - "sleeping": "😴", - "mask": "😷", - "face_with_thermometer": "🤒", - "face_with_head_bandage": "🤕", - "nauseated_face": "🤢", - "vomiting_face": "🤮", - "sneezing_face": "🤧", - "hot_face": "🥵", - "cold_face": "🥶", - "woozy_face": "🥴", - "dizzy_face": "😵", - "face_with_spiral_eyes": "😵‍💫", - "exploding_head": "🤯", - "cowboy_hat_face": "🤠", - "partying_face": "🥳", - "disguised_face": "🥸", - "sunglasses": "😎", - "nerd_face": "🤓", - "monocle_face": "🧐", - "confused": "😕", - "face_with_diagonal_mouth": "🫤", - "worried": "😟", - "slightly_frowning_face": "🙁", - "frowning_face": "☹️", - "open_mouth": "😮", - "hushed": "😯", - "astonished": "😲", - "flushed": "😳", - "pleading_face": "🥺", - "face_holding_back_tears": "🥹", - "frowning": "😦", - "anguished": "😧", - "fearful": "😨", - "cold_sweat": "😰", - "disappointed_relieved": "😥", - "cry": "😢", - "sob": "😭", - "scream": "😱", - "confounded": "😖", - "persevere": "😣", - "disappointed": "😞", - "sweat": "😓", - "weary": "😩", - "tired_face": "😫", - "yawning_face": "🥱", - "triumph": "😤", - "rage": "😡", - "pout": "😡", - "angry": "😠", - "cursing_face": "🤬", - "smiling_imp": "😈", - "imp": "👿", - "skull": "💀", - "skull_and_crossbones": "☠️", - "hankey": "💩", - "poop": "💩", - "shit": "💩", - "clown_face": "🤡", - "japanese_ogre": "👹", - "japanese_goblin": "👺", - "ghost": "👻", - "alien": "👽", - "space_invader": "👾", - "robot": "🤖", - "smiley_cat": "😺", - "smile_cat": "😸", - "joy_cat": "😹", - "heart_eyes_cat": "😻", - "smirk_cat": "😼", - "kissing_cat": "😽", - "scream_cat": "🙀", - "crying_cat_face": "😿", - "pouting_cat": "😾", - "see_no_evil": "🙈", - "hear_no_evil": "🙉", - "speak_no_evil": "🙊", - "love_letter": "💌", - "cupid": "💘", - "gift_heart": "💝", - "sparkling_heart": "💖", - "heartpulse": "💗", - "heartbeat": "💓", - "revolving_hearts": "💞", - "two_hearts": "💕", - "heart_decoration": "💟", - "heavy_heart_exclamation": "❣️", - "broken_heart": "💔", - "heart_on_fire": "❤️‍🔥", - "mending_heart": "❤️‍🩹", - "heart": "❤️", - "pink_heart": "🩷", - "orange_heart": "🧡", - "yellow_heart": "💛", - "green_heart": "💚", - "blue_heart": "💙", - "light_blue_heart": "🩵", - "purple_heart": "💜", - "brown_heart": "🤎", - "black_heart": "🖤", - "grey_heart": "🩶", - "white_heart": "🤍", - "kiss": "💋", - "anger": "💢", - "boom": "💥", - "collision": "💥", - "dizzy": "💫", - "sweat_drops": "💦", - "dash": "💨", - "hole": "🕳️", - "speech_balloon": "💬", - "eye_speech_bubble": "👁️‍🗨️", - "left_speech_bubble": "🗨️", - "right_anger_bubble": "🗯️", - "thought_balloon": "💭", - "zzz": "💤", - "wave": "👋", - "raised_back_of_hand": "🤚", - "raised_hand_with_fingers_splayed": "🖐️", - "hand": "✋", - "raised_hand": "✋", - "vulcan_salute": "🖖", - "rightwards_hand": "🫱", - "leftwards_hand": "🫲", - "palm_down_hand": "🫳", - "palm_up_hand": "🫴", - "leftwards_pushing_hand": "🫷", - "rightwards_pushing_hand": "🫸", - "ok_hand": "👌", - "pinched_fingers": "🤌", - "pinching_hand": "🤏", - "v": "✌️", - "crossed_fingers": "🤞", - "hand_with_index_finger_and_thumb_crossed": "🫰", - "love_you_gesture": "🤟", - "metal": "🤘", - "call_me_hand": "🤙", - "point_left": "👈", - "point_right": "👉", - "point_up_2": "👆", - "middle_finger": "🖕", - "fu": "🖕", - "point_down": "👇", - "point_up": "☝️", - "index_pointing_at_the_viewer": "🫵", - "+1": "👍", - "thumbsup": "👍", - "-1": "👎", - "thumbsdown": "👎", - "fist_raised": "✊", - "fist": "✊", - "fist_oncoming": "👊", - "facepunch": "👊", - "punch": "👊", - "fist_left": "🤛", - "fist_right": "🤜", - "clap": "👏", - "raised_hands": "🙌", - "heart_hands": "🫶", - "open_hands": "👐", - "palms_up_together": "🤲", - "handshake": "🤝", - "pray": "🙏", - "writing_hand": "✍️", - "nail_care": "💅", - "selfie": "🤳", - "muscle": "💪", - "mechanical_arm": "🦾", - "mechanical_leg": "🦿", - "leg": "🦵", - "foot": "🦶", - "ear": "👂", - "ear_with_hearing_aid": "🦻", - "nose": "👃", - "brain": "🧠", - "anatomical_heart": "🫀", - "lungs": "🫁", - "tooth": "🦷", - "bone": "🦴", - "eyes": "👀", - "eye": "👁️", - "tongue": "👅", - "lips": "👄", - "biting_lip": "🫦", - "baby": "👶", - "child": "🧒", - "boy": "👦", - "girl": "👧", - "adult": "🧑", - "blond_haired_person": "👱", - "man": "👨", - "bearded_person": "🧔", - "man_beard": "🧔‍♂️", - "woman_beard": "🧔‍♀️", - "red_haired_man": "👨‍🦰", - "curly_haired_man": "👨‍🦱", - "white_haired_man": "👨‍🦳", - "bald_man": "👨‍🦲", - "woman": "👩", - "red_haired_woman": "👩‍🦰", - "person_red_hair": "🧑‍🦰", - "curly_haired_woman": "👩‍🦱", - "person_curly_hair": "🧑‍🦱", - "white_haired_woman": "👩‍🦳", - "person_white_hair": "🧑‍🦳", - "bald_woman": "👩‍🦲", - "person_bald": "🧑‍🦲", - "blond_haired_woman": "👱‍♀️", - "blonde_woman": "👱‍♀️", - "blond_haired_man": "👱‍♂️", - "older_adult": "🧓", - "older_man": "👴", - "older_woman": "👵", - "frowning_person": "🙍", - "frowning_man": "🙍‍♂️", - "frowning_woman": "🙍‍♀️", - "pouting_face": "🙎", - "pouting_man": "🙎‍♂️", - "pouting_woman": "🙎‍♀️", - "no_good": "🙅", - "no_good_man": "🙅‍♂️", - "ng_man": "🙅‍♂️", - "no_good_woman": "🙅‍♀️", - "ng_woman": "🙅‍♀️", - "ok_person": "🙆", - "ok_man": "🙆‍♂️", - "ok_woman": "🙆‍♀️", - "tipping_hand_person": "💁", - "information_desk_person": "💁", - "tipping_hand_man": "💁‍♂️", - "sassy_man": "💁‍♂️", - "tipping_hand_woman": "💁‍♀️", - "sassy_woman": "💁‍♀️", - "raising_hand": "🙋", - "raising_hand_man": "🙋‍♂️", - "raising_hand_woman": "🙋‍♀️", - "deaf_person": "🧏", - "deaf_man": "🧏‍♂️", - "deaf_woman": "🧏‍♀️", - "bow": "🙇", - "bowing_man": "🙇‍♂️", - "bowing_woman": "🙇‍♀️", - "facepalm": "🤦", - "man_facepalming": "🤦‍♂️", - "woman_facepalming": "🤦‍♀️", - "shrug": "🤷", - "man_shrugging": "🤷‍♂️", - "woman_shrugging": "🤷‍♀️", - "health_worker": "🧑‍⚕️", - "man_health_worker": "👨‍⚕️", - "woman_health_worker": "👩‍⚕️", - "student": "🧑‍🎓", - "man_student": "👨‍🎓", - "woman_student": "👩‍🎓", - "teacher": "🧑‍🏫", - "man_teacher": "👨‍🏫", - "woman_teacher": "👩‍🏫", - "judge": "🧑‍⚖️", - "man_judge": "👨‍⚖️", - "woman_judge": "👩‍⚖️", - "farmer": "🧑‍🌾", - "man_farmer": "👨‍🌾", - "woman_farmer": "👩‍🌾", - "cook": "🧑‍🍳", - "man_cook": "👨‍🍳", - "woman_cook": "👩‍🍳", - "mechanic": "🧑‍🔧", - "man_mechanic": "👨‍🔧", - "woman_mechanic": "👩‍🔧", - "factory_worker": "🧑‍🏭", - "man_factory_worker": "👨‍🏭", - "woman_factory_worker": "👩‍🏭", - "office_worker": "🧑‍💼", - "man_office_worker": "👨‍💼", - "woman_office_worker": "👩‍💼", - "scientist": "🧑‍🔬", - "man_scientist": "👨‍🔬", - "woman_scientist": "👩‍🔬", - "technologist": "🧑‍💻", - "man_technologist": "👨‍💻", - "woman_technologist": "👩‍💻", - "singer": "🧑‍🎤", - "man_singer": "👨‍🎤", - "woman_singer": "👩‍🎤", - "artist": "🧑‍🎨", - "man_artist": "👨‍🎨", - "woman_artist": "👩‍🎨", - "pilot": "🧑‍✈️", - "man_pilot": "👨‍✈️", - "woman_pilot": "👩‍✈️", - "astronaut": "🧑‍🚀", - "man_astronaut": "👨‍🚀", - "woman_astronaut": "👩‍🚀", - "firefighter": "🧑‍🚒", - "man_firefighter": "👨‍🚒", - "woman_firefighter": "👩‍🚒", - "police_officer": "👮", - "cop": "👮", - "policeman": "👮‍♂️", - "policewoman": "👮‍♀️", - "detective": "🕵️", - "male_detective": "🕵️‍♂️", - "female_detective": "🕵️‍♀️", - "guard": "💂", - "guardsman": "💂‍♂️", - "guardswoman": "💂‍♀️", - "ninja": "🥷", - "construction_worker": "👷", - "construction_worker_man": "👷‍♂️", - "construction_worker_woman": "👷‍♀️", - "person_with_crown": "🫅", - "prince": "🤴", - "princess": "👸", - "person_with_turban": "👳", - "man_with_turban": "👳‍♂️", - "woman_with_turban": "👳‍♀️", - "man_with_gua_pi_mao": "👲", - "woman_with_headscarf": "🧕", - "person_in_tuxedo": "🤵", - "man_in_tuxedo": "🤵‍♂️", - "woman_in_tuxedo": "🤵‍♀️", - "person_with_veil": "👰", - "man_with_veil": "👰‍♂️", - "woman_with_veil": "👰‍♀️", - "bride_with_veil": "👰‍♀️", - "pregnant_woman": "🤰", - "pregnant_man": "🫃", - "pregnant_person": "🫄", - "breast_feeding": "🤱", - "woman_feeding_baby": "👩‍🍼", - "man_feeding_baby": "👨‍🍼", - "person_feeding_baby": "🧑‍🍼", - "angel": "👼", - "santa": "🎅", - "mrs_claus": "🤶", - "mx_claus": "🧑‍🎄", - "superhero": "🦸", - "superhero_man": "🦸‍♂️", - "superhero_woman": "🦸‍♀️", - "supervillain": "🦹", - "supervillain_man": "🦹‍♂️", - "supervillain_woman": "🦹‍♀️", - "mage": "🧙", - "mage_man": "🧙‍♂️", - "mage_woman": "🧙‍♀️", - "fairy": "🧚", - "fairy_man": "🧚‍♂️", - "fairy_woman": "🧚‍♀️", - "vampire": "🧛", - "vampire_man": "🧛‍♂️", - "vampire_woman": "🧛‍♀️", - "merperson": "🧜", - "merman": "🧜‍♂️", - "mermaid": "🧜‍♀️", - "elf": "🧝", - "elf_man": "🧝‍♂️", - "elf_woman": "🧝‍♀️", - "genie": "🧞", - "genie_man": "🧞‍♂️", - "genie_woman": "🧞‍♀️", - "zombie": "🧟", - "zombie_man": "🧟‍♂️", - "zombie_woman": "🧟‍♀️", - "troll": "🧌", - "massage": "💆", - "massage_man": "💆‍♂️", - "massage_woman": "💆‍♀️", - "haircut": "💇", - "haircut_man": "💇‍♂️", - "haircut_woman": "💇‍♀️", - "walking": "🚶", - "walking_man": "🚶‍♂️", - "walking_woman": "🚶‍♀️", - "standing_person": "🧍", - "standing_man": "🧍‍♂️", - "standing_woman": "🧍‍♀️", - "kneeling_person": "🧎", - "kneeling_man": "🧎‍♂️", - "kneeling_woman": "🧎‍♀️", - "person_with_probing_cane": "🧑‍🦯", - "man_with_probing_cane": "👨‍🦯", - "woman_with_probing_cane": "👩‍🦯", - "person_in_motorized_wheelchair": "🧑‍🦼", - "man_in_motorized_wheelchair": "👨‍🦼", - "woman_in_motorized_wheelchair": "👩‍🦼", - "person_in_manual_wheelchair": "🧑‍🦽", - "man_in_manual_wheelchair": "👨‍🦽", - "woman_in_manual_wheelchair": "👩‍🦽", - "runner": "🏃", - "running": "🏃", - "running_man": "🏃‍♂️", - "running_woman": "🏃‍♀️", - "woman_dancing": "💃", - "dancer": "💃", - "man_dancing": "🕺", - "business_suit_levitating": "🕴️", - "dancers": "👯", - "dancing_men": "👯‍♂️", - "dancing_women": "👯‍♀️", - "sauna_person": "🧖", - "sauna_man": "🧖‍♂️", - "sauna_woman": "🧖‍♀️", - "climbing": "🧗", - "climbing_man": "🧗‍♂️", - "climbing_woman": "🧗‍♀️", - "person_fencing": "🤺", - "horse_racing": "🏇", - "skier": "⛷️", - "snowboarder": "🏂", - "golfing": "🏌️", - "golfing_man": "🏌️‍♂️", - "golfing_woman": "🏌️‍♀️", - "surfer": "🏄", - "surfing_man": "🏄‍♂️", - "surfing_woman": "🏄‍♀️", - "rowboat": "🚣", - "rowing_man": "🚣‍♂️", - "rowing_woman": "🚣‍♀️", - "swimmer": "🏊", - "swimming_man": "🏊‍♂️", - "swimming_woman": "🏊‍♀️", - "bouncing_ball_person": "⛹️", - "bouncing_ball_man": "⛹️‍♂️", - "basketball_man": "⛹️‍♂️", - "bouncing_ball_woman": "⛹️‍♀️", - "basketball_woman": "⛹️‍♀️", - "weight_lifting": "🏋️", - "weight_lifting_man": "🏋️‍♂️", - "weight_lifting_woman": "🏋️‍♀️", - "bicyclist": "🚴", - "biking_man": "🚴‍♂️", - "biking_woman": "🚴‍♀️", - "mountain_bicyclist": "🚵", - "mountain_biking_man": "🚵‍♂️", - "mountain_biking_woman": "🚵‍♀️", - "cartwheeling": "🤸", - "man_cartwheeling": "🤸‍♂️", - "woman_cartwheeling": "🤸‍♀️", - "wrestling": "🤼", - "men_wrestling": "🤼‍♂️", - "women_wrestling": "🤼‍♀️", - "water_polo": "🤽", - "man_playing_water_polo": "🤽‍♂️", - "woman_playing_water_polo": "🤽‍♀️", - "handball_person": "🤾", - "man_playing_handball": "🤾‍♂️", - "woman_playing_handball": "🤾‍♀️", - "juggling_person": "🤹", - "man_juggling": "🤹‍♂️", - "woman_juggling": "🤹‍♀️", - "lotus_position": "🧘", - "lotus_position_man": "🧘‍♂️", - "lotus_position_woman": "🧘‍♀️", - "bath": "🛀", - "sleeping_bed": "🛌", - "people_holding_hands": "🧑‍🤝‍🧑", - "two_women_holding_hands": "👭", - "couple": "👫", - "two_men_holding_hands": "👬", - "couplekiss": "💏", - "couplekiss_man_woman": "👩‍❤️‍💋‍👨", - "couplekiss_man_man": "👨‍❤️‍💋‍👨", - "couplekiss_woman_woman": "👩‍❤️‍💋‍👩", - "couple_with_heart": "💑", - "couple_with_heart_woman_man": "👩‍❤️‍👨", - "couple_with_heart_man_man": "👨‍❤️‍👨", - "couple_with_heart_woman_woman": "👩‍❤️‍👩", - "family": "👪", - "family_man_woman_boy": "👨‍👩‍👦", - "family_man_woman_girl": "👨‍👩‍👧", - "family_man_woman_girl_boy": "👨‍👩‍👧‍👦", - "family_man_woman_boy_boy": "👨‍👩‍👦‍👦", - "family_man_woman_girl_girl": "👨‍👩‍👧‍👧", - "family_man_man_boy": "👨‍👨‍👦", - "family_man_man_girl": "👨‍👨‍👧", - "family_man_man_girl_boy": "👨‍👨‍👧‍👦", - "family_man_man_boy_boy": "👨‍👨‍👦‍👦", - "family_man_man_girl_girl": "👨‍👨‍👧‍👧", - "family_woman_woman_boy": "👩‍👩‍👦", - "family_woman_woman_girl": "👩‍👩‍👧", - "family_woman_woman_girl_boy": "👩‍👩‍👧‍👦", - "family_woman_woman_boy_boy": "👩‍👩‍👦‍👦", - "family_woman_woman_girl_girl": "👩‍👩‍👧‍👧", - "family_man_boy": "👨‍👦", - "family_man_boy_boy": "👨‍👦‍👦", - "family_man_girl": "👨‍👧", - "family_man_girl_boy": "👨‍👧‍👦", - "family_man_girl_girl": "👨‍👧‍👧", - "family_woman_boy": "👩‍👦", - "family_woman_boy_boy": "👩‍👦‍👦", - "family_woman_girl": "👩‍👧", - "family_woman_girl_boy": "👩‍👧‍👦", - "family_woman_girl_girl": "👩‍👧‍👧", - "speaking_head": "🗣️", - "bust_in_silhouette": "👤", - "busts_in_silhouette": "👥", - "people_hugging": "🫂", - "footprints": "👣", - "monkey_face": "🐵", - "monkey": "🐒", - "gorilla": "🦍", - "orangutan": "🦧", - "dog": "🐶", - "dog2": "🐕", - "guide_dog": "🦮", - "service_dog": "🐕‍🦺", - "poodle": "🐩", - "wolf": "🐺", - "fox_face": "🦊", - "raccoon": "🦝", - "cat": "🐱", - "cat2": "🐈", - "black_cat": "🐈‍⬛", - "lion": "🦁", - "tiger": "🐯", - "tiger2": "🐅", - "leopard": "🐆", - "horse": "🐴", - "moose": "🫎", - "donkey": "🫏", - "racehorse": "🐎", - "unicorn": "🦄", - "zebra": "🦓", - "deer": "🦌", - "bison": "🦬", - "cow": "🐮", - "ox": "🐂", - "water_buffalo": "🐃", - "cow2": "🐄", - "pig": "🐷", - "pig2": "🐖", - "boar": "🐗", - "pig_nose": "🐽", - "ram": "🐏", - "sheep": "🐑", - "goat": "🐐", - "dromedary_camel": "🐪", - "camel": "🐫", - "llama": "🦙", - "giraffe": "🦒", - "elephant": "🐘", - "mammoth": "🦣", - "rhinoceros": "🦏", - "hippopotamus": "🦛", - "mouse": "🐭", - "mouse2": "🐁", - "rat": "🐀", - "hamster": "🐹", - "rabbit": "🐰", - "rabbit2": "🐇", - "chipmunk": "🐿️", - "beaver": "🦫", - "hedgehog": "🦔", - "bat": "🦇", - "bear": "🐻", - "polar_bear": "🐻‍❄️", - "koala": "🐨", - "panda_face": "🐼", - "sloth": "🦥", - "otter": "🦦", - "skunk": "🦨", - "kangaroo": "🦘", - "badger": "🦡", - "feet": "🐾", - "paw_prints": "🐾", - "turkey": "🦃", - "chicken": "🐔", - "rooster": "🐓", - "hatching_chick": "🐣", - "baby_chick": "🐤", - "hatched_chick": "🐥", - "bird": "🐦", - "penguin": "🐧", - "dove": "🕊️", - "eagle": "🦅", - "duck": "🦆", - "swan": "🦢", - "owl": "🦉", - "dodo": "🦤", - "feather": "🪶", - "flamingo": "🦩", - "peacock": "🦚", - "parrot": "🦜", - "wing": "🪽", - "black_bird": "🐦‍⬛", - "goose": "🪿", - "frog": "🐸", - "crocodile": "🐊", - "turtle": "🐢", - "lizard": "🦎", - "snake": "🐍", - "dragon_face": "🐲", - "dragon": "🐉", - "sauropod": "🦕", - "t-rex": "🦖", - "whale": "🐳", - "whale2": "🐋", - "dolphin": "🐬", - "flipper": "🐬", - "seal": "🦭", - "fish": "🐟", - "tropical_fish": "🐠", - "blowfish": "🐡", - "shark": "🦈", - "octopus": "🐙", - "shell": "🐚", - "coral": "🪸", - "jellyfish": "🪼", - "snail": "🐌", - "butterfly": "🦋", - "bug": "🐛", - "ant": "🐜", - "bee": "🐝", - "honeybee": "🐝", - "beetle": "🪲", - "lady_beetle": "🐞", - "cricket": "🦗", - "cockroach": "🪳", - "spider": "🕷️", - "spider_web": "🕸️", - "scorpion": "🦂", - "mosquito": "🦟", - "fly": "🪰", - "worm": "🪱", - "microbe": "🦠", - "bouquet": "💐", - "cherry_blossom": "🌸", - "white_flower": "💮", - "lotus": "🪷", - "rosette": "🏵️", - "rose": "🌹", - "wilted_flower": "🥀", - "hibiscus": "🌺", - "sunflower": "🌻", - "blossom": "🌼", - "tulip": "🌷", - "hyacinth": "🪻", - "seedling": "🌱", - "potted_plant": "🪴", - "evergreen_tree": "🌲", - "deciduous_tree": "🌳", - "palm_tree": "🌴", - "cactus": "🌵", - "ear_of_rice": "🌾", - "herb": "🌿", - "shamrock": "☘️", - "four_leaf_clover": "🍀", - "maple_leaf": "🍁", - "fallen_leaf": "🍂", - "leaves": "🍃", - "empty_nest": "🪹", - "nest_with_eggs": "🪺", - "mushroom": "🍄", - "grapes": "🍇", - "melon": "🍈", - "watermelon": "🍉", - "tangerine": "🍊", - "orange": "🍊", - "mandarin": "🍊", - "lemon": "🍋", - "banana": "🍌", - "pineapple": "🍍", - "mango": "🥭", - "apple": "🍎", - "green_apple": "🍏", - "pear": "🍐", - "peach": "🍑", - "cherries": "🍒", - "strawberry": "🍓", - "blueberries": "🫐", - "kiwi_fruit": "🥝", - "tomato": "🍅", - "olive": "🫒", - "coconut": "🥥", - "avocado": "🥑", - "eggplant": "🍆", - "potato": "🥔", - "carrot": "🥕", - "corn": "🌽", - "hot_pepper": "🌶️", - "bell_pepper": "🫑", - "cucumber": "🥒", - "leafy_green": "🥬", - "broccoli": "🥦", - "garlic": "🧄", - "onion": "🧅", - "peanuts": "🥜", - "beans": "🫘", - "chestnut": "🌰", - "ginger_root": "🫚", - "pea_pod": "🫛", - "bread": "🍞", - "croissant": "🥐", - "baguette_bread": "🥖", - "flatbread": "🫓", - "pretzel": "🥨", - "bagel": "🥯", - "pancakes": "🥞", - "waffle": "🧇", - "cheese": "🧀", - "meat_on_bone": "🍖", - "poultry_leg": "🍗", - "cut_of_meat": "🥩", - "bacon": "🥓", - "hamburger": "🍔", - "fries": "🍟", - "pizza": "🍕", - "hotdog": "🌭", - "sandwich": "🥪", - "taco": "🌮", - "burrito": "🌯", - "tamale": "🫔", - "stuffed_flatbread": "🥙", - "falafel": "🧆", - "egg": "🥚", - "fried_egg": "🍳", - "shallow_pan_of_food": "🥘", - "stew": "🍲", - "fondue": "🫕", - "bowl_with_spoon": "🥣", - "green_salad": "🥗", - "popcorn": "🍿", - "butter": "🧈", - "salt": "🧂", - "canned_food": "🥫", - "bento": "🍱", - "rice_cracker": "🍘", - "rice_ball": "🍙", - "rice": "🍚", - "curry": "🍛", - "ramen": "🍜", - "spaghetti": "🍝", - "sweet_potato": "🍠", - "oden": "🍢", - "sushi": "🍣", - "fried_shrimp": "🍤", - "fish_cake": "🍥", - "moon_cake": "🥮", - "dango": "🍡", - "dumpling": "🥟", - "fortune_cookie": "🥠", - "takeout_box": "🥡", - "crab": "🦀", - "lobster": "🦞", - "shrimp": "🦐", - "squid": "🦑", - "oyster": "🦪", - "icecream": "🍦", - "shaved_ice": "🍧", - "ice_cream": "🍨", - "doughnut": "🍩", - "cookie": "🍪", - "birthday": "🎂", - "cake": "🍰", - "cupcake": "🧁", - "pie": "🥧", - "chocolate_bar": "🍫", - "candy": "🍬", - "lollipop": "🍭", - "custard": "🍮", - "honey_pot": "🍯", - "baby_bottle": "🍼", - "milk_glass": "🥛", - "coffee": "☕", - "teapot": "🫖", - "tea": "🍵", - "sake": "🍶", - "champagne": "🍾", - "wine_glass": "🍷", - "cocktail": "🍸", - "tropical_drink": "🍹", - "beer": "🍺", - "beers": "🍻", - "clinking_glasses": "🥂", - "tumbler_glass": "🥃", - "pouring_liquid": "🫗", - "cup_with_straw": "🥤", - "bubble_tea": "🧋", - "beverage_box": "🧃", - "mate": "🧉", - "ice_cube": "🧊", - "chopsticks": "🥢", - "plate_with_cutlery": "🍽️", - "fork_and_knife": "🍴", - "spoon": "🥄", - "hocho": "🔪", - "knife": "🔪", - "jar": "🫙", - "amphora": "🏺", - "earth_africa": "🌍", - "earth_americas": "🌎", - "earth_asia": "🌏", - "globe_with_meridians": "🌐", - "world_map": "🗺️", - "japan": "🗾", - "compass": "🧭", - "mountain_snow": "🏔️", - "mountain": "⛰️", - "volcano": "🌋", - "mount_fuji": "🗻", - "camping": "🏕️", - "beach_umbrella": "🏖️", - "desert": "🏜️", - "desert_island": "🏝️", - "national_park": "🏞️", - "stadium": "🏟️", - "classical_building": "🏛️", - "building_construction": "🏗️", - "bricks": "🧱", - "rock": "🪨", - "wood": "🪵", - "hut": "🛖", - "houses": "🏘️", - "derelict_house": "🏚️", - "house": "🏠", - "house_with_garden": "🏡", - "office": "🏢", - "post_office": "🏣", - "european_post_office": "🏤", - "hospital": "🏥", - "bank": "🏦", - "hotel": "🏨", - "love_hotel": "🏩", - "convenience_store": "🏪", - "school": "🏫", - "department_store": "🏬", - "factory": "🏭", - "japanese_castle": "🏯", - "european_castle": "🏰", - "wedding": "💒", - "tokyo_tower": "🗼", - "statue_of_liberty": "🗽", - "church": "⛪", - "mosque": "🕌", - "hindu_temple": "🛕", - "synagogue": "🕍", - "shinto_shrine": "⛩️", - "kaaba": "🕋", - "fountain": "⛲", - "tent": "⛺", - "foggy": "🌁", - "night_with_stars": "🌃", - "cityscape": "🏙️", - "sunrise_over_mountains": "🌄", - "sunrise": "🌅", - "city_sunset": "🌆", - "city_sunrise": "🌇", - "bridge_at_night": "🌉", - "hotsprings": "♨️", - "carousel_horse": "🎠", - "playground_slide": "🛝", - "ferris_wheel": "🎡", - "roller_coaster": "🎢", - "barber": "💈", - "circus_tent": "🎪", - "steam_locomotive": "🚂", - "railway_car": "🚃", - "bullettrain_side": "🚄", - "bullettrain_front": "🚅", - "train2": "🚆", - "metro": "🚇", - "light_rail": "🚈", - "station": "🚉", - "tram": "🚊", - "monorail": "🚝", - "mountain_railway": "🚞", - "train": "🚋", - "bus": "🚌", - "oncoming_bus": "🚍", - "trolleybus": "🚎", - "minibus": "🚐", - "ambulance": "🚑", - "fire_engine": "🚒", - "police_car": "🚓", - "oncoming_police_car": "🚔", - "taxi": "🚕", - "oncoming_taxi": "🚖", - "car": "🚗", - "red_car": "🚗", - "oncoming_automobile": "🚘", - "blue_car": "🚙", - "pickup_truck": "🛻", - "truck": "🚚", - "articulated_lorry": "🚛", - "tractor": "🚜", - "racing_car": "🏎️", - "motorcycle": "🏍️", - "motor_scooter": "🛵", - "manual_wheelchair": "🦽", - "motorized_wheelchair": "🦼", - "auto_rickshaw": "🛺", - "bike": "🚲", - "kick_scooter": "🛴", - "skateboard": "🛹", - "roller_skate": "🛼", - "busstop": "🚏", - "motorway": "🛣️", - "railway_track": "🛤️", - "oil_drum": "🛢️", - "fuelpump": "⛽", - "wheel": "🛞", - "rotating_light": "🚨", - "traffic_light": "🚥", - "vertical_traffic_light": "🚦", - "stop_sign": "🛑", - "construction": "🚧", - "anchor": "⚓", - "ring_buoy": "🛟", - "boat": "⛵", - "sailboat": "⛵", - "canoe": "🛶", - "speedboat": "🚤", - "passenger_ship": "🛳️", - "ferry": "⛴️", - "motor_boat": "🛥️", - "ship": "🚢", - "airplane": "✈️", - "small_airplane": "🛩️", - "flight_departure": "🛫", - "flight_arrival": "🛬", - "parachute": "🪂", - "seat": "💺", - "helicopter": "🚁", - "suspension_railway": "🚟", - "mountain_cableway": "🚠", - "aerial_tramway": "🚡", - "artificial_satellite": "🛰️", - "rocket": "🚀", - "flying_saucer": "🛸", - "bellhop_bell": "🛎️", - "luggage": "🧳", - "hourglass": "⌛", - "hourglass_flowing_sand": "⏳", - "watch": "⌚", - "alarm_clock": "⏰", - "stopwatch": "⏱️", - "timer_clock": "⏲️", - "mantelpiece_clock": "🕰️", - "clock12": "🕛", - "clock1230": "🕧", - "clock1": "🕐", - "clock130": "🕜", - "clock2": "🕑", - "clock230": "🕝", - "clock3": "🕒", - "clock330": "🕞", - "clock4": "🕓", - "clock430": "🕟", - "clock5": "🕔", - "clock530": "🕠", - "clock6": "🕕", - "clock630": "🕡", - "clock7": "🕖", - "clock730": "🕢", - "clock8": "🕗", - "clock830": "🕣", - "clock9": "🕘", - "clock930": "🕤", - "clock10": "🕙", - "clock1030": "🕥", - "clock11": "🕚", - "clock1130": "🕦", - "new_moon": "🌑", - "waxing_crescent_moon": "🌒", - "first_quarter_moon": "🌓", - "moon": "🌔", - "waxing_gibbous_moon": "🌔", - "full_moon": "🌕", - "waning_gibbous_moon": "🌖", - "last_quarter_moon": "🌗", - "waning_crescent_moon": "🌘", - "crescent_moon": "🌙", - "new_moon_with_face": "🌚", - "first_quarter_moon_with_face": "🌛", - "last_quarter_moon_with_face": "🌜", - "thermometer": "🌡️", - "sunny": "☀️", - "full_moon_with_face": "🌝", - "sun_with_face": "🌞", - "ringed_planet": "🪐", - "star": "⭐", - "star2": "🌟", - "stars": "🌠", - "milky_way": "🌌", - "cloud": "☁️", - "partly_sunny": "⛅", - "cloud_with_lightning_and_rain": "⛈️", - "sun_behind_small_cloud": "🌤️", - "sun_behind_large_cloud": "🌥️", - "sun_behind_rain_cloud": "🌦️", - "cloud_with_rain": "🌧️", - "cloud_with_snow": "🌨️", - "cloud_with_lightning": "🌩️", - "tornado": "🌪️", - "fog": "🌫️", - "wind_face": "🌬️", - "cyclone": "🌀", - "rainbow": "🌈", - "closed_umbrella": "🌂", - "open_umbrella": "☂️", - "umbrella": "☔", - "parasol_on_ground": "⛱️", - "zap": "⚡", - "snowflake": "❄️", - "snowman_with_snow": "☃️", - "snowman": "⛄", - "comet": "☄️", - "fire": "🔥", - "droplet": "💧", - "ocean": "🌊", - "jack_o_lantern": "🎃", - "christmas_tree": "🎄", - "fireworks": "🎆", - "sparkler": "🎇", - "firecracker": "🧨", - "sparkles": "✨", - "balloon": "🎈", - "tada": "🎉", - "confetti_ball": "🎊", - "tanabata_tree": "🎋", - "bamboo": "🎍", - "dolls": "🎎", - "flags": "🎏", - "wind_chime": "🎐", - "rice_scene": "🎑", - "red_envelope": "🧧", - "ribbon": "🎀", - "gift": "🎁", - "reminder_ribbon": "🎗️", - "tickets": "🎟️", - "ticket": "🎫", - "medal_military": "🎖️", - "trophy": "🏆", - "medal_sports": "🏅", - "1st_place_medal": "🥇", - "2nd_place_medal": "🥈", - "3rd_place_medal": "🥉", - "soccer": "⚽", - "baseball": "⚾", - "softball": "🥎", - "basketball": "🏀", - "volleyball": "🏐", - "football": "🏈", - "rugby_football": "🏉", - "tennis": "🎾", - "flying_disc": "🥏", - "bowling": "🎳", - "cricket_game": "🏏", - "field_hockey": "🏑", - "ice_hockey": "🏒", - "lacrosse": "🥍", - "ping_pong": "🏓", - "badminton": "🏸", - "boxing_glove": "🥊", - "martial_arts_uniform": "🥋", - "goal_net": "🥅", - "golf": "⛳", - "ice_skate": "⛸️", - "fishing_pole_and_fish": "🎣", - "diving_mask": "🤿", - "running_shirt_with_sash": "🎽", - "ski": "🎿", - "sled": "🛷", - "curling_stone": "🥌", - "dart": "🎯", - "yo_yo": "🪀", - "kite": "🪁", - "gun": "🔫", - "8ball": "🎱", - "crystal_ball": "🔮", - "magic_wand": "🪄", - "video_game": "🎮", - "joystick": "🕹️", - "slot_machine": "🎰", - "game_die": "🎲", - "jigsaw": "🧩", - "teddy_bear": "🧸", - "pinata": "🪅", - "mirror_ball": "🪩", - "nesting_dolls": "🪆", - "spades": "♠️", - "hearts": "♥️", - "diamonds": "♦️", - "clubs": "♣️", - "chess_pawn": "♟️", - "black_joker": "🃏", - "mahjong": "🀄", - "flower_playing_cards": "🎴", - "performing_arts": "🎭", - "framed_picture": "🖼️", - "art": "🎨", - "thread": "🧵", - "sewing_needle": "🪡", - "yarn": "🧶", - "knot": "🪢", - "eyeglasses": "👓", - "dark_sunglasses": "🕶️", - "goggles": "🥽", - "lab_coat": "🥼", - "safety_vest": "🦺", - "necktie": "👔", - "shirt": "👕", - "tshirt": "👕", - "jeans": "👖", - "scarf": "🧣", - "gloves": "🧤", - "coat": "🧥", - "socks": "🧦", - "dress": "👗", - "kimono": "👘", - "sari": "🥻", - "one_piece_swimsuit": "🩱", - "swim_brief": "🩲", - "shorts": "🩳", - "bikini": "👙", - "womans_clothes": "👚", - "folding_hand_fan": "🪭", - "purse": "👛", - "handbag": "👜", - "pouch": "👝", - "shopping": "🛍️", - "school_satchel": "🎒", - "thong_sandal": "🩴", - "mans_shoe": "👞", - "shoe": "👞", - "athletic_shoe": "👟", - "hiking_boot": "🥾", - "flat_shoe": "🥿", - "high_heel": "👠", - "sandal": "👡", - "ballet_shoes": "🩰", - "boot": "👢", - "hair_pick": "🪮", - "crown": "👑", - "womans_hat": "👒", - "tophat": "🎩", - "mortar_board": "🎓", - "billed_cap": "🧢", - "military_helmet": "🪖", - "rescue_worker_helmet": "⛑️", - "prayer_beads": "📿", - "lipstick": "💄", - "ring": "💍", - "gem": "💎", - "mute": "🔇", - "speaker": "🔈", - "sound": "🔉", - "loud_sound": "🔊", - "loudspeaker": "📢", - "mega": "📣", - "postal_horn": "📯", - "bell": "🔔", - "no_bell": "🔕", - "musical_score": "🎼", - "musical_note": "🎵", - "notes": "🎶", - "studio_microphone": "🎙️", - "level_slider": "🎚️", - "control_knobs": "🎛️", - "microphone": "🎤", - "headphones": "🎧", - "radio": "📻", - "saxophone": "🎷", - "accordion": "🪗", - "guitar": "🎸", - "musical_keyboard": "🎹", - "trumpet": "🎺", - "violin": "🎻", - "banjo": "🪕", - "drum": "🥁", - "long_drum": "🪘", - "maracas": "🪇", - "flute": "🪈", - "iphone": "📱", - "calling": "📲", - "phone": "☎️", - "telephone": "☎️", - "telephone_receiver": "📞", - "pager": "📟", - "fax": "📠", - "battery": "🔋", - "low_battery": "🪫", - "electric_plug": "🔌", - "computer": "💻", - "desktop_computer": "🖥️", - "printer": "🖨️", - "keyboard": "⌨️", - "computer_mouse": "🖱️", - "trackball": "🖲️", - "minidisc": "💽", - "floppy_disk": "💾", - "cd": "💿", - "dvd": "📀", - "abacus": "🧮", - "movie_camera": "🎥", - "film_strip": "🎞️", - "film_projector": "📽️", - "clapper": "🎬", - "tv": "📺", - "camera": "📷", - "camera_flash": "📸", - "video_camera": "📹", - "vhs": "📼", - "mag": "🔍", - "mag_right": "🔎", - "candle": "🕯️", - "bulb": "💡", - "flashlight": "🔦", - "izakaya_lantern": "🏮", - "lantern": "🏮", - "diya_lamp": "🪔", - "notebook_with_decorative_cover": "📔", - "closed_book": "📕", - "book": "📖", - "open_book": "📖", - "green_book": "📗", - "blue_book": "📘", - "orange_book": "📙", - "books": "📚", - "notebook": "📓", - "ledger": "📒", - "page_with_curl": "📃", - "scroll": "📜", - "page_facing_up": "📄", - "newspaper": "📰", - "newspaper_roll": "🗞️", - "bookmark_tabs": "📑", - "bookmark": "🔖", - "label": "🏷️", - "moneybag": "💰", - "coin": "🪙", - "yen": "💴", - "dollar": "💵", - "euro": "💶", - "pound": "💷", - "money_with_wings": "💸", - "credit_card": "💳", - "receipt": "🧾", - "chart": "💹", - "envelope": "✉️", - "email": "📧", - "e-mail": "📧", - "incoming_envelope": "📨", - "envelope_with_arrow": "📩", - "outbox_tray": "📤", - "inbox_tray": "📥", - "package": "📦", - "mailbox": "📫", - "mailbox_closed": "📪", - "mailbox_with_mail": "📬", - "mailbox_with_no_mail": "📭", - "postbox": "📮", - "ballot_box": "🗳️", - "pencil2": "✏️", - "black_nib": "✒️", - "fountain_pen": "🖋️", - "pen": "🖊️", - "paintbrush": "🖌️", - "crayon": "🖍️", - "memo": "📝", - "pencil": "📝", - "briefcase": "💼", - "file_folder": "📁", - "open_file_folder": "📂", - "card_index_dividers": "🗂️", - "date": "📅", - "calendar": "📆", - "spiral_notepad": "🗒️", - "spiral_calendar": "🗓️", - "card_index": "📇", - "chart_with_upwards_trend": "📈", - "chart_with_downwards_trend": "📉", - "bar_chart": "📊", - "clipboard": "📋", - "pushpin": "📌", - "round_pushpin": "📍", - "paperclip": "📎", - "paperclips": "🖇️", - "straight_ruler": "📏", - "triangular_ruler": "📐", - "scissors": "✂️", - "card_file_box": "🗃️", - "file_cabinet": "🗄️", - "wastebasket": "🗑️", - "lock": "🔒", - "unlock": "🔓", - "lock_with_ink_pen": "🔏", - "closed_lock_with_key": "🔐", - "key": "🔑", - "old_key": "🗝️", - "hammer": "🔨", - "axe": "🪓", - "pick": "⛏️", - "hammer_and_pick": "⚒️", - "hammer_and_wrench": "🛠️", - "dagger": "🗡️", - "crossed_swords": "⚔️", - "bomb": "💣", - "boomerang": "🪃", - "bow_and_arrow": "🏹", - "shield": "🛡️", - "carpentry_saw": "🪚", - "wrench": "🔧", - "screwdriver": "🪛", - "nut_and_bolt": "🔩", - "gear": "⚙️", - "clamp": "🗜️", - "balance_scale": "⚖️", - "probing_cane": "🦯", - "link": "🔗", - "chains": "⛓️", - "hook": "🪝", - "toolbox": "🧰", - "magnet": "🧲", - "ladder": "🪜", - "alembic": "⚗️", - "test_tube": "🧪", - "petri_dish": "🧫", - "dna": "🧬", - "microscope": "🔬", - "telescope": "🔭", - "satellite": "📡", - "syringe": "💉", - "drop_of_blood": "🩸", - "pill": "💊", - "adhesive_bandage": "🩹", - "crutch": "🩼", - "stethoscope": "🩺", - "x_ray": "🩻", - "door": "🚪", - "elevator": "🛗", - "mirror": "🪞", - "window": "🪟", - "bed": "🛏️", - "couch_and_lamp": "🛋️", - "chair": "🪑", - "toilet": "🚽", - "plunger": "🪠", - "shower": "🚿", - "bathtub": "🛁", - "mouse_trap": "🪤", - "razor": "🪒", - "lotion_bottle": "🧴", - "safety_pin": "🧷", - "broom": "🧹", - "basket": "🧺", - "roll_of_paper": "🧻", - "bucket": "🪣", - "soap": "🧼", - "bubbles": "🫧", - "toothbrush": "🪥", - "sponge": "🧽", - "fire_extinguisher": "🧯", - "shopping_cart": "🛒", - "smoking": "🚬", - "coffin": "⚰️", - "headstone": "🪦", - "funeral_urn": "⚱️", - "nazar_amulet": "🧿", - "hamsa": "🪬", - "moyai": "🗿", - "placard": "🪧", - "identification_card": "🪪", - "atm": "🏧", - "put_litter_in_its_place": "🚮", - "potable_water": "🚰", - "wheelchair": "♿", - "mens": "🚹", - "womens": "🚺", - "restroom": "🚻", - "baby_symbol": "🚼", - "wc": "🚾", - "passport_control": "🛂", - "customs": "🛃", - "baggage_claim": "🛄", - "left_luggage": "🛅", - "warning": "⚠️", - "children_crossing": "🚸", - "no_entry": "⛔", - "no_entry_sign": "🚫", - "no_bicycles": "🚳", - "no_smoking": "🚭", - "do_not_litter": "🚯", - "non-potable_water": "🚱", - "no_pedestrians": "🚷", - "no_mobile_phones": "📵", - "underage": "🔞", - "radioactive": "☢️", - "biohazard": "☣️", - "arrow_up": "⬆️", - "arrow_upper_right": "↗️", - "arrow_right": "➡️", - "arrow_lower_right": "↘️", - "arrow_down": "⬇️", - "arrow_lower_left": "↙️", - "arrow_left": "⬅️", - "arrow_upper_left": "↖️", - "arrow_up_down": "↕️", - "left_right_arrow": "↔️", - "leftwards_arrow_with_hook": "↩️", - "arrow_right_hook": "↪️", - "arrow_heading_up": "⤴️", - "arrow_heading_down": "⤵️", - "arrows_clockwise": "🔃", - "arrows_counterclockwise": "🔄", - "back": "🔙", - "end": "🔚", - "on": "🔛", - "soon": "🔜", - "top": "🔝", - "place_of_worship": "🛐", - "atom_symbol": "⚛️", - "om": "🕉️", - "star_of_david": "✡️", - "wheel_of_dharma": "☸️", - "yin_yang": "☯️", - "latin_cross": "✝️", - "orthodox_cross": "☦️", - "star_and_crescent": "☪️", - "peace_symbol": "☮️", - "menorah": "🕎", - "six_pointed_star": "🔯", - "khanda": "🪯", - "aries": "♈", - "taurus": "♉", - "gemini": "♊", - "cancer": "♋", - "leo": "♌", - "virgo": "♍", - "libra": "♎", - "scorpius": "♏", - "sagittarius": "♐", - "capricorn": "♑", - "aquarius": "♒", - "pisces": "♓", - "ophiuchus": "⛎", - "twisted_rightwards_arrows": "🔀", - "repeat": "🔁", - "repeat_one": "🔂", - "arrow_forward": "▶️", - "fast_forward": "⏩", - "next_track_button": "⏭️", - "play_or_pause_button": "⏯️", - "arrow_backward": "◀️", - "rewind": "⏪", - "previous_track_button": "⏮️", - "arrow_up_small": "🔼", - "arrow_double_up": "⏫", - "arrow_down_small": "🔽", - "arrow_double_down": "⏬", - "pause_button": "⏸️", - "stop_button": "⏹️", - "record_button": "⏺️", - "eject_button": "⏏️", - "cinema": "🎦", - "low_brightness": "🔅", - "high_brightness": "🔆", - "signal_strength": "📶", - "wireless": "🛜", - "vibration_mode": "📳", - "mobile_phone_off": "📴", - "female_sign": "♀️", - "male_sign": "♂️", - "transgender_symbol": "⚧️", - "heavy_multiplication_x": "✖️", - "heavy_plus_sign": "➕", - "heavy_minus_sign": "➖", - "heavy_division_sign": "➗", - "heavy_equals_sign": "🟰", - "infinity": "♾️", - "bangbang": "‼️", - "interrobang": "⁉️", - "question": "❓", - "grey_question": "❔", - "grey_exclamation": "❕", - "exclamation": "❗", - "heavy_exclamation_mark": "❗", - "wavy_dash": "〰️", - "currency_exchange": "💱", - "heavy_dollar_sign": "💲", - "medical_symbol": "⚕️", - "recycle": "♻️", - "fleur_de_lis": "⚜️", - "trident": "🔱", - "name_badge": "📛", - "beginner": "🔰", - "o": "⭕", - "white_check_mark": "✅", - "ballot_box_with_check": "☑️", - "heavy_check_mark": "✔️", - "x": "❌", - "negative_squared_cross_mark": "❎", - "curly_loop": "➰", - "loop": "➿", - "part_alternation_mark": "〽️", - "eight_spoked_asterisk": "✳️", - "eight_pointed_black_star": "✴️", - "sparkle": "❇️", - "copyright": "©️", - "registered": "®️", - "tm": "™️", - "hash": "#️⃣", - "asterisk": "*️⃣", - "zero": "0️⃣", - "one": "1️⃣", - "two": "2️⃣", - "three": "3️⃣", - "four": "4️⃣", - "five": "5️⃣", - "six": "6️⃣", - "seven": "7️⃣", - "eight": "8️⃣", - "nine": "9️⃣", - "keycap_ten": "🔟", - "capital_abcd": "🔠", - "abcd": "🔡", - "symbols": "🔣", - "abc": "🔤", - "a": "🅰️", - "ab": "🆎", - "b": "🅱️", - "cl": "🆑", - "cool": "🆒", - "free": "🆓", - "information_source": "ℹ️", - "id": "🆔", - "m": "Ⓜ️", - "new": "🆕", - "ng": "🆖", - "o2": "🅾️", - "ok": "🆗", - "parking": "🅿️", - "sos": "🆘", - "up": "🆙", - "vs": "🆚", - "koko": "🈁", - "sa": "🈂️", - "ideograph_advantage": "🉐", - "accept": "🉑", - "congratulations": "㊗️", - "secret": "㊙️", - "u6e80": "🈵", - "red_circle": "🔴", - "orange_circle": "🟠", - "yellow_circle": "🟡", - "green_circle": "🟢", - "large_blue_circle": "🔵", - "purple_circle": "🟣", - "brown_circle": "🟤", - "black_circle": "⚫", - "white_circle": "⚪", - "red_square": "🟥", - "orange_square": "🟧", - "yellow_square": "🟨", - "green_square": "🟩", - "blue_square": "🟦", - "purple_square": "🟪", - "brown_square": "🟫", - "black_large_square": "⬛", - "white_large_square": "⬜", - "black_medium_square": "◼️", - "white_medium_square": "◻️", - "black_medium_small_square": "◾", - "white_medium_small_square": "◽", - "black_small_square": "▪️", - "white_small_square": "▫️", - "large_orange_diamond": "🔶", - "large_blue_diamond": "🔷", - "small_orange_diamond": "🔸", - "small_blue_diamond": "🔹", - "small_red_triangle": "🔺", - "small_red_triangle_down": "🔻", - "diamond_shape_with_a_dot_inside": "💠", - "radio_button": "🔘", - "white_square_button": "🔳", - "black_square_button": "🔲", - "checkered_flag": "🏁", - "triangular_flag_on_post": "🚩", - "crossed_flags": "🎌", - "black_flag": "🏴", - "white_flag": "🏳️", - "rainbow_flag": "🏳️‍🌈", - "transgender_flag": "🏳️‍⚧️", - "pirate_flag": "🏴‍☠️", - "ascension_island": "🇦🇨", - "andorra": "🇦🇩", - "united_arab_emirates": "🇦🇪", - "afghanistan": "🇦🇫", - "antigua_barbuda": "🇦🇬", - "anguilla": "🇦🇮", - "albania": "🇦🇱", - "armenia": "🇦🇲", - "angola": "🇦🇴", - "antarctica": "🇦🇶", - "argentina": "🇦🇷", - "american_samoa": "🇦🇸", - "austria": "🇦🇹", - "australia": "🇦🇺", - "aruba": "🇦🇼", - "aland_islands": "🇦🇽", - "azerbaijan": "🇦🇿", - "bosnia_herzegovina": "🇧🇦", - "barbados": "🇧🇧", - "bangladesh": "🇧🇩", - "belgium": "🇧🇪", - "burkina_faso": "🇧🇫", - "bulgaria": "🇧🇬", - "bahrain": "🇧🇭", - "burundi": "🇧🇮", - "benin": "🇧🇯", - "st_barthelemy": "🇧🇱", - "bermuda": "🇧🇲", - "brunei": "🇧🇳", - "bolivia": "🇧🇴", - "caribbean_netherlands": "🇧🇶", - "brazil": "🇧🇷", - "bahamas": "🇧🇸", - "bhutan": "🇧🇹", - "bouvet_island": "🇧🇻", - "botswana": "🇧🇼", - "belarus": "🇧🇾", - "belize": "🇧🇿", - "canada": "🇨🇦", - "cocos_islands": "🇨🇨", - "congo_kinshasa": "🇨🇩", - "central_african_republic": "🇨🇫", - "congo_brazzaville": "🇨🇬", - "switzerland": "🇨🇭", - "cote_divoire": "🇨🇮", - "cook_islands": "🇨🇰", - "chile": "🇨🇱", - "cameroon": "🇨🇲", - "cn": "🇨🇳", - "colombia": "🇨🇴", - "clipperton_island": "🇨🇵", - "costa_rica": "🇨🇷", - "cuba": "🇨🇺", - "cape_verde": "🇨🇻", - "curacao": "🇨🇼", - "christmas_island": "🇨🇽", - "cyprus": "🇨🇾", - "czech_republic": "🇨🇿", - "de": "🇩🇪", - "diego_garcia": "🇩🇬", - "djibouti": "🇩🇯", - "denmark": "🇩🇰", - "dominica": "🇩🇲", - "dominican_republic": "🇩🇴", - "algeria": "🇩🇿", - "ceuta_melilla": "🇪🇦", - "ecuador": "🇪🇨", - "estonia": "🇪🇪", - "egypt": "🇪🇬", - "western_sahara": "🇪🇭", - "eritrea": "🇪🇷", - "es": "🇪🇸", - "ethiopia": "🇪🇹", - "eu": "🇪🇺", - "european_union": "🇪🇺", - "finland": "🇫🇮", - "fiji": "🇫🇯", - "falkland_islands": "🇫🇰", - "micronesia": "🇫🇲", - "faroe_islands": "🇫🇴", - "fr": "🇫🇷", - "gabon": "🇬🇦", - "gb": "🇬🇧", - "uk": "🇬🇧", - "grenada": "🇬🇩", - "georgia": "🇬🇪", - "french_guiana": "🇬🇫", - "guernsey": "🇬🇬", - "ghana": "🇬🇭", - "gibraltar": "🇬🇮", - "greenland": "🇬🇱", - "gambia": "🇬🇲", - "guinea": "🇬🇳", - "guadeloupe": "🇬🇵", - "equatorial_guinea": "🇬🇶", - "greece": "🇬🇷", - "south_georgia_south_sandwich_islands": "🇬🇸", - "guatemala": "🇬🇹", - "guam": "🇬🇺", - "guinea_bissau": "🇬🇼", - "guyana": "🇬🇾", - "hong_kong": "🇭🇰", - "heard_mcdonald_islands": "🇭🇲", - "honduras": "🇭🇳", - "croatia": "🇭🇷", - "haiti": "🇭🇹", - "hungary": "🇭🇺", - "canary_islands": "🇮🇨", - "indonesia": "🇮🇩", - "ireland": "🇮🇪", - "israel": "🇮🇱", - "isle_of_man": "🇮🇲", - "india": "🇮🇳", - "british_indian_ocean_territory": "🇮🇴", - "iraq": "🇮🇶", - "iran": "🇮🇷", - "iceland": "🇮🇸", - "it": "🇮🇹", - "jersey": "🇯🇪", - "jamaica": "🇯🇲", - "jordan": "🇯🇴", - "jp": "🇯🇵", - "kenya": "🇰🇪", - "kyrgyzstan": "🇰🇬", - "cambodia": "🇰🇭", - "kiribati": "🇰🇮", - "comoros": "🇰🇲", - "st_kitts_nevis": "🇰🇳", - "north_korea": "🇰🇵", - "kr": "🇰🇷", - "kuwait": "🇰🇼", - "cayman_islands": "🇰🇾", - "kazakhstan": "🇰🇿", - "laos": "🇱🇦", - "lebanon": "🇱🇧", - "st_lucia": "🇱🇨", - "liechtenstein": "🇱🇮", - "sri_lanka": "🇱🇰", - "liberia": "🇱🇷", - "lesotho": "🇱🇸", - "lithuania": "🇱🇹", - "luxembourg": "🇱🇺", - "latvia": "🇱🇻", - "libya": "🇱🇾", - "morocco": "🇲🇦", - "monaco": "🇲🇨", - "moldova": "🇲🇩", - "montenegro": "🇲🇪", - "st_martin": "🇲🇫", - "madagascar": "🇲🇬", - "marshall_islands": "🇲🇭", - "macedonia": "🇲🇰", - "mali": "🇲🇱", - "myanmar": "🇲🇲", - "mongolia": "🇲🇳", - "macau": "🇲🇴", - "northern_mariana_islands": "🇲🇵", - "martinique": "🇲🇶", - "mauritania": "🇲🇷", - "montserrat": "🇲🇸", - "malta": "🇲🇹", - "mauritius": "🇲🇺", - "maldives": "🇲🇻", - "malawi": "🇲🇼", - "mexico": "🇲🇽", - "malaysia": "🇲🇾", - "mozambique": "🇲🇿", - "namibia": "🇳🇦", - "new_caledonia": "🇳🇨", - "niger": "🇳🇪", - "norfolk_island": "🇳🇫", - "nigeria": "🇳🇬", - "nicaragua": "🇳🇮", - "netherlands": "🇳🇱", - "norway": "🇳🇴", - "nepal": "🇳🇵", - "nauru": "🇳🇷", - "niue": "🇳🇺", - "new_zealand": "🇳🇿", - "oman": "🇴🇲", - "panama": "🇵🇦", - "peru": "🇵🇪", - "french_polynesia": "🇵🇫", - "papua_new_guinea": "🇵🇬", - "philippines": "🇵🇭", - "pakistan": "🇵🇰", - "poland": "🇵🇱", - "st_pierre_miquelon": "🇵🇲", - "pitcairn_islands": "🇵🇳", - "puerto_rico": "🇵🇷", - "palestinian_territories": "🇵🇸", - "portugal": "🇵🇹", - "palau": "🇵🇼", - "paraguay": "🇵🇾", - "qatar": "🇶🇦", - "reunion": "🇷🇪", - "romania": "🇷🇴", - "serbia": "🇷🇸", - "ru": "🇷🇺", - "rwanda": "🇷🇼", - "saudi_arabia": "🇸🇦", - "solomon_islands": "🇸🇧", - "seychelles": "🇸🇨", - "sudan": "🇸🇩", - "sweden": "🇸🇪", - "singapore": "🇸🇬", - "st_helena": "🇸🇭", - "slovenia": "🇸🇮", - "svalbard_jan_mayen": "🇸🇯", - "slovakia": "🇸🇰", - "sierra_leone": "🇸🇱", - "san_marino": "🇸🇲", - "senegal": "🇸🇳", - "somalia": "🇸🇴", - "suriname": "🇸🇷", - "south_sudan": "🇸🇸", - "sao_tome_principe": "🇸🇹", - "el_salvador": "🇸🇻", - "sint_maarten": "🇸🇽", - "syria": "🇸🇾", - "swaziland": "🇸🇿", - "tristan_da_cunha": "🇹🇦", - "turks_caicos_islands": "🇹🇨", - "chad": "🇹🇩", - "french_southern_territories": "🇹🇫", - "togo": "🇹🇬", - "thailand": "🇹🇭", - "tajikistan": "🇹🇯", - "tokelau": "🇹🇰", - "timor_leste": "🇹🇱", - "turkmenistan": "🇹🇲", - "tunisia": "🇹🇳", - "tonga": "🇹🇴", - "tr": "🇹🇷", - "trinidad_tobago": "🇹🇹", - "tuvalu": "🇹🇻", - "taiwan": "🇹🇼", - "tanzania": "🇹🇿", - "ukraine": "🇺🇦", - "uganda": "🇺🇬", - "us_outlying_islands": "🇺🇲", - "united_nations": "🇺🇳", - "us": "🇺🇸", - "uruguay": "🇺🇾", - "uzbekistan": "🇺🇿", - "vatican_city": "🇻🇦", - "st_vincent_grenadines": "🇻🇨", - "venezuela": "🇻🇪", - "british_virgin_islands": "🇻🇬", - "us_virgin_islands": "🇻🇮", - "vietnam": "🇻🇳", - "vanuatu": "🇻🇺", - "wallis_futuna": "🇼🇫", - "samoa": "🇼🇸", - "kosovo": "🇽🇰", - "yemen": "🇾🇪", - "mayotte": "🇾🇹", - "south_africa": "🇿🇦", - "zambia": "🇿🇲", - "zimbabwe": "🇿🇼", - "england": "🏴󠁧󠁢󠁥󠁮󠁧󠁿", - "scotland": "🏴󠁧󠁢󠁳󠁣󠁴󠁿", - "wales": "🏴󠁧󠁢󠁷󠁬󠁳󠁿" -}; - -export default emojies; diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/light.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/light.ts deleted file mode 100644 index acaed2f..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/light.ts +++ /dev/null @@ -1,158 +0,0 @@ -// Generated, don't edit -import { EmojiDefs } from '../normalize_opts'; - -const emojies: EmojiDefs = { - "grinning": "😀", - "smiley": "😃", - "smile": "😄", - "grin": "😁", - "laughing": "😆", - "satisfied": "😆", - "sweat_smile": "😅", - "joy": "😂", - "wink": "😉", - "blush": "😊", - "innocent": "😇", - "heart_eyes": "😍", - "kissing_heart": "😘", - "kissing": "😗", - "kissing_closed_eyes": "😚", - "kissing_smiling_eyes": "😙", - "yum": "😋", - "stuck_out_tongue": "😛", - "stuck_out_tongue_winking_eye": "😜", - "stuck_out_tongue_closed_eyes": "😝", - "neutral_face": "😐", - "expressionless": "😑", - "no_mouth": "😶", - "smirk": "😏", - "unamused": "😒", - "relieved": "😌", - "pensive": "😔", - "sleepy": "😪", - "sleeping": "😴", - "mask": "😷", - "dizzy_face": "😵", - "sunglasses": "😎", - "confused": "😕", - "worried": "😟", - "open_mouth": "😮", - "hushed": "😯", - "astonished": "😲", - "flushed": "😳", - "frowning": "😦", - "anguished": "😧", - "fearful": "😨", - "cold_sweat": "😰", - "disappointed_relieved": "😥", - "cry": "😢", - "sob": "😭", - "scream": "😱", - "confounded": "😖", - "persevere": "😣", - "disappointed": "😞", - "sweat": "😓", - "weary": "😩", - "tired_face": "😫", - "rage": "😡", - "pout": "😡", - "angry": "😠", - "smiling_imp": "😈", - "smiley_cat": "😺", - "smile_cat": "😸", - "joy_cat": "😹", - "heart_eyes_cat": "😻", - "smirk_cat": "😼", - "kissing_cat": "😽", - "scream_cat": "🙀", - "crying_cat_face": "😿", - "pouting_cat": "😾", - "heart": "❤️", - "hand": "✋", - "raised_hand": "✋", - "v": "✌️", - "point_up": "☝️", - "fist_raised": "✊", - "fist": "✊", - "monkey_face": "🐵", - "cat": "🐱", - "cow": "🐮", - "mouse": "🐭", - "coffee": "☕", - "hotsprings": "♨️", - "anchor": "⚓", - "airplane": "✈️", - "hourglass": "⌛", - "watch": "⌚", - "sunny": "☀️", - "star": "⭐", - "cloud": "☁️", - "umbrella": "☔", - "zap": "⚡", - "snowflake": "❄️", - "sparkles": "✨", - "black_joker": "🃏", - "mahjong": "🀄", - "phone": "☎️", - "telephone": "☎️", - "envelope": "✉️", - "pencil2": "✏️", - "black_nib": "✒️", - "scissors": "✂️", - "wheelchair": "♿", - "warning": "⚠️", - "aries": "♈", - "taurus": "♉", - "gemini": "♊", - "cancer": "♋", - "leo": "♌", - "virgo": "♍", - "libra": "♎", - "scorpius": "♏", - "sagittarius": "♐", - "capricorn": "♑", - "aquarius": "♒", - "pisces": "♓", - "heavy_multiplication_x": "✖️", - "heavy_plus_sign": "➕", - "heavy_minus_sign": "➖", - "heavy_division_sign": "➗", - "bangbang": "‼️", - "interrobang": "⁉️", - "question": "❓", - "grey_question": "❔", - "grey_exclamation": "❕", - "exclamation": "❗", - "heavy_exclamation_mark": "❗", - "wavy_dash": "〰️", - "recycle": "♻️", - "white_check_mark": "✅", - "ballot_box_with_check": "☑️", - "heavy_check_mark": "✔️", - "x": "❌", - "negative_squared_cross_mark": "❎", - "curly_loop": "➰", - "loop": "➿", - "part_alternation_mark": "〽️", - "eight_spoked_asterisk": "✳️", - "eight_pointed_black_star": "✴️", - "sparkle": "❇️", - "copyright": "©️", - "registered": "®️", - "tm": "™️", - "information_source": "ℹ️", - "m": "Ⓜ️", - "black_circle": "⚫", - "white_circle": "⚪", - "black_large_square": "⬛", - "white_large_square": "⬜", - "black_medium_square": "◼️", - "white_medium_square": "◻️", - "black_medium_small_square": "◾", - "white_medium_small_square": "◽", - "black_small_square": "▪️", - "white_small_square": "▫️" -}; - -export default emojies; - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/shortcuts.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/shortcuts.ts deleted file mode 100644 index 418c6c0..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/data/shortcuts.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Emoticons -> Emoji mapping. -// -// (!) Some patterns skipped, to avoid collisions -// without increase matcher complicity. Than can change in future. -// -// Places to look for more emoticons info: -// -// - http://en.wikipedia.org/wiki/List_of_emoticons#Western -// - https://github.com/wooorm/emoticon/blob/master/Support.md -// - http://factoryjoe.com/projects/emoticons/ -// - -import { EmojiShortcuts } from '../normalize_opts'; - -const shortcuts: EmojiShortcuts = { - angry: ['>:(', '>:-('], - blush: [':")', ':-")'], - broken_heart: ['): void { - const defaults: EmojiOptions = { - defs: emojies_defs, - shortcuts: emojies_shortcuts, - enabled: [] - }; - - const opts = md.utils.assign({}, defaults, options || {}) as EmojiOptions; - - bare_emoji_plugin(md, opts); -} - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/light.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/light.ts deleted file mode 100644 index 74f8321..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/light.ts +++ /dev/null @@ -1,21 +0,0 @@ -import MarkdownIt from 'markdown-it'; -import emojies_defs from './data/light'; -import emojies_shortcuts from './data/shortcuts'; -import bare_emoji_plugin from './bare'; -import { EmojiOptions } from './normalize_opts'; - -/** - * Light emoji 插件(包含常用的 emoji 数据) - */ -export default function emoji_plugin(md: MarkdownIt, options?: Partial): void { - const defaults: EmojiOptions = { - defs: emojies_defs, - shortcuts: emojies_shortcuts, - enabled: [] - }; - - const opts = md.utils.assign({}, defaults, options || {}) as EmojiOptions; - - bare_emoji_plugin(md, opts); -} - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/normalize_opts.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/normalize_opts.ts deleted file mode 100644 index 53eb426..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/normalize_opts.ts +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Emoji 定义类型 - */ -export interface EmojiDefs { - [key: string]: string; -} - -/** - * Emoji 快捷方式类型 - */ -export interface EmojiShortcuts { - [key: string]: string | string[]; -} - -/** - * 输入选项接口 - */ -export interface EmojiOptions { - defs: EmojiDefs; - shortcuts: EmojiShortcuts; - enabled: string[]; -} - -/** - * 标准化后的选项接口 - */ -export interface NormalizedEmojiOptions { - defs: EmojiDefs; - shortcuts: { [key: string]: string }; - scanRE: RegExp; - replaceRE: RegExp; -} - -/** - * 转义正则表达式特殊字符 - */ -function quoteRE(str: string): string { - return str.replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&'); -} - -/** - * 将输入选项转换为更可用的格式并编译搜索正则表达式 - */ -export default function normalize_opts(options: EmojiOptions): NormalizedEmojiOptions { - let emojies = options.defs; - - // Filter emojies by whitelist, if needed - if (options.enabled.length) { - emojies = Object.keys(emojies).reduce((acc: EmojiDefs, key: string) => { - if (options.enabled.indexOf(key) >= 0) acc[key] = emojies[key]; - return acc; - }, {}); - } - - // Flatten shortcuts to simple object: { alias: emoji_name } - const shortcuts = Object.keys(options.shortcuts).reduce((acc: { [key: string]: string }, key: string) => { - // Skip aliases for filtered emojies, to reduce regexp - if (!emojies[key]) return acc; - - if (Array.isArray(options.shortcuts[key])) { - (options.shortcuts[key] as string[]).forEach((alias: string) => { acc[alias] = key; }); - return acc; - } - - acc[options.shortcuts[key] as string] = key; - return acc; - }, {}); - - const keys = Object.keys(emojies); - let names: string; - - // If no definitions are given, return empty regex to avoid replacements with 'undefined'. - if (keys.length === 0) { - names = '^$'; - } else { - // Compile regexp - names = keys - .map((name: string) => { return `:${name}:`; }) - .concat(Object.keys(shortcuts)) - .sort() - .reverse() - .map((name: string) => { return quoteRE(name); }) - .join('|'); - } - const scanRE = RegExp(names); - const replaceRE = RegExp(names, 'g'); - - return { - defs: emojies, - shortcuts, - scanRE, - replaceRE - }; -} - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/render.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/render.ts deleted file mode 100644 index db40f94..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/render.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Token } from 'markdown-it'; - -/** - * Emoji 渲染函数 - */ -export default function emoji_html(tokens: Token[], idx: number): string { - return tokens[idx].content; -} - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/replace.ts b/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/replace.ts deleted file mode 100644 index 556fb54..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-emojis/lib/replace.ts +++ /dev/null @@ -1,97 +0,0 @@ -import MarkdownIt, { StateCore, Token } from 'markdown-it'; -import { EmojiDefs } from './normalize_opts'; - -/** - * Emoji 和快捷方式替换逻辑 - * - * 注意:理论上,在内联链中解析 :smile: 并只留下快捷方式会更快。 - * 但是,谁在乎呢... - */ -export default function create_rule( - md: MarkdownIt, - emojies: EmojiDefs, - shortcuts: { [key: string]: string }, - scanRE: RegExp, - replaceRE: RegExp -) { - const arrayReplaceAt = md.utils.arrayReplaceAt; - const ucm = md.utils.lib.ucmicro; - const has = md.utils.has; - const ZPCc = new RegExp([ucm.Z.source, ucm.P.source, ucm.Cc.source].join('|')); - - function splitTextToken(text: string, level: number, TokenConstructor: any): Token[] { - let last_pos = 0; - const nodes: Token[] = []; - - text.replace(replaceRE, function (match: string, offset: number, src: string): string { - let emoji_name: string; - // Validate emoji name - if (has(shortcuts, match)) { - // replace shortcut with full name - emoji_name = shortcuts[match]; - - // Don't allow letters before any shortcut (as in no ":/" in http://) - if (offset > 0 && !ZPCc.test(src[offset - 1])) return ''; - - // Don't allow letters after any shortcut - if (offset + match.length < src.length && !ZPCc.test(src[offset + match.length])) { - return ''; - } - } else { - emoji_name = match.slice(1, -1); - } - - // Add new tokens to pending list - if (offset > last_pos) { - const token = new TokenConstructor('text', '', 0); - token.content = text.slice(last_pos, offset); - nodes.push(token); - } - - const token = new TokenConstructor('emoji', '', 0); - token.markup = emoji_name; - token.content = emojies[emoji_name]; - nodes.push(token); - - last_pos = offset + match.length; - return ''; - }); - - if (last_pos < text.length) { - const token = new TokenConstructor('text', '', 0); - token.content = text.slice(last_pos); - nodes.push(token); - } - - return nodes; - } - - return function emoji_replace(state: StateCore): void { - let token: Token; - const blockTokens = state.tokens; - let autolinkLevel = 0; - - for (let j = 0, l = blockTokens.length; j < l; j++) { - if (blockTokens[j].type !== 'inline') { continue; } - let tokens = blockTokens[j].children!; - - // We scan from the end, to keep position when new tags added. - // Use reversed logic in links start/end match - for (let i = tokens.length - 1; i >= 0; i--) { - token = tokens[i]; - - if (token.type === 'link_open' || token.type === 'link_close') { - if (token.info === 'auto') { autolinkLevel -= token.nesting; } - } - - if (token.type === 'text' && autolinkLevel === 0 && scanRE.test(token.content)) { - // replace current node - blockTokens[j].children = tokens = arrayReplaceAt( - tokens, i, splitTextToken(token.content, token.level, state.Token) - ); - } - } - } - }; -} - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-footnote/index.ts b/frontend/src/common/markdown-it/plugins/markdown-it-footnote/index.ts deleted file mode 100644 index 1f80bba..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-footnote/index.ts +++ /dev/null @@ -1,390 +0,0 @@ -import MarkdownIt, {Renderer, StateBlock, StateCore, StateInline, Token} from 'markdown-it'; - -/** - * 脚注元数据接口 - */ -interface FootnoteMeta { - id: number; - subId: number; - label: string; -} - -/** - * 脚注列表项接口 - */ -interface FootnoteItem { - label?: string; - content?: string; - tokens?: Token[]; - count: number; -} - -/** - * 环境接口 - */ -interface FootnoteEnv { - footnotes?: { - refs?: { [key: string]: number }; - list?: FootnoteItem[]; - }; - docId?: string; -} - -/// ///////////////////////////////////////////////////////////////////////////// -// Renderer partials - -function render_footnote_anchor_name(tokens: Token[], idx: number, options: any, env: FootnoteEnv): string { - const n = Number(tokens[idx].meta.id + 1).toString(); - let prefix = ''; - - if (typeof env.docId === 'string') prefix = `-${env.docId}-`; - - return prefix + n; -} - -function render_footnote_caption(tokens: Token[], idx: number): string { - let n = Number(tokens[idx].meta.id + 1).toString(); - - if (tokens[idx].meta.subId > 0) n += `:${tokens[idx].meta.subId}`; - - return `[${n}]`; -} - -function render_footnote_ref(tokens: Token[], idx: number, options: any, env: FootnoteEnv, slf: Renderer): string { - const id = slf.rules.footnote_anchor_name!(tokens, idx, options, env, slf); - const caption = slf.rules.footnote_caption!(tokens, idx, options, env, slf); - let refid = id; - - if (tokens[idx].meta.subId > 0) refid += `:${tokens[idx].meta.subId}`; - - return `${caption}`; -} - -function render_footnote_block_open(tokens: Token[], idx: number, options: any): string { - return (options.xhtmlOut ? '
\n' : '
\n') + - '
\n' + - '
    \n'; -} - -function render_footnote_block_close(): string { - return '
\n
\n'; -} - -function render_footnote_open(tokens: Token[], idx: number, options: any, env: FootnoteEnv, slf: Renderer): string { - let id = slf.rules.footnote_anchor_name!(tokens, idx, options, env, slf); - - if (tokens[idx].meta.subId > 0) id += `:${tokens[idx].meta.subId}`; - - return `
  • `; -} - -function render_footnote_close(): string { - return '
  • \n'; -} - -function render_footnote_anchor(tokens: Token[], idx: number, options: any, env: FootnoteEnv, slf: Renderer): string { - let id = slf.rules.footnote_anchor_name!(tokens, idx, options, env, slf); - - if (tokens[idx].meta.subId > 0) id += `:${tokens[idx].meta.subId}`; - - /* ↩ with escape code to prevent display as Apple Emoji on iOS */ - return ` \u21a9\uFE0E`; -} - -/** - * markdown-it-footnote 插件 - * 用于支持脚注语法 - */ -export default function footnote_plugin(md: MarkdownIt): void { - const parseLinkLabel = md.helpers.parseLinkLabel; - const isSpace = md.utils.isSpace; - - md.renderer.rules.footnote_ref = render_footnote_ref; - md.renderer.rules.footnote_block_open = render_footnote_block_open; - md.renderer.rules.footnote_block_close = render_footnote_block_close; - md.renderer.rules.footnote_open = render_footnote_open; - md.renderer.rules.footnote_close = render_footnote_close; - md.renderer.rules.footnote_anchor = render_footnote_anchor; - - // helpers (only used in other rules, no tokens are attached to those) - md.renderer.rules.footnote_caption = render_footnote_caption; - md.renderer.rules.footnote_anchor_name = render_footnote_anchor_name; - - // Process footnote block definition - function footnote_def(state: StateBlock, startLine: number, endLine: number, silent: boolean): boolean { - const start = state.bMarks[startLine] + state.tShift[startLine]; - const max = state.eMarks[startLine]; - - // line should be at least 5 chars - "[^x]:" - if (start + 4 > max) return false; - - if (state.src.charCodeAt(start) !== 0x5B/* [ */) return false; - if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) return false; - - let pos: number; - - for (pos = start + 2; pos < max; pos++) { - if (state.src.charCodeAt(pos) === 0x20) return false; - if (state.src.charCodeAt(pos) === 0x5D /* ] */) { - break; - } - } - - if (pos === start + 2) return false; // no empty footnote labels - if (pos + 1 >= max || state.src.charCodeAt(++pos) !== 0x3A /* : */) return false; - if (silent) return true; - pos++; - - const env = state.env as FootnoteEnv; - if (!env.footnotes) env.footnotes = {}; - if (!env.footnotes.refs) env.footnotes.refs = {}; - const label = state.src.slice(start + 2, pos - 2); - env.footnotes.refs[`:${label}`] = -1; - - const token_fref_o = new state.Token('footnote_reference_open', '', 1); - token_fref_o.meta = { label }; - token_fref_o.level = state.level++; - state.tokens.push(token_fref_o); - - const oldBMark = state.bMarks[startLine]; - const oldTShift = state.tShift[startLine]; - const oldSCount = state.sCount[startLine]; - const oldParentType = state.parentType; - - const posAfterColon = pos; - const initial = state.sCount[startLine] + pos - (state.bMarks[startLine] + state.tShift[startLine]); - let offset = initial; - - while (pos < max) { - const ch = state.src.charCodeAt(pos); - - if (isSpace(ch)) { - if (ch === 0x09) { - offset += 4 - offset % 4; - } else { - offset++; - } - } else { - break; - } - - pos++; - } - - state.tShift[startLine] = pos - posAfterColon; - state.sCount[startLine] = offset - initial; - - state.bMarks[startLine] = posAfterColon; - state.blkIndent += 4; - state.parentType = 'footnote' as any; - - if (state.sCount[startLine] < state.blkIndent) { - state.sCount[startLine] += state.blkIndent; - } - - state.md.block.tokenize(state, startLine, endLine); - - state.parentType = oldParentType; - state.blkIndent -= 4; - state.tShift[startLine] = oldTShift; - state.sCount[startLine] = oldSCount; - state.bMarks[startLine] = oldBMark; - - const token_fref_c = new state.Token('footnote_reference_close', '', -1); - token_fref_c.level = --state.level; - state.tokens.push(token_fref_c); - - return true; - } - - // Process inline footnotes (^[...]) - function footnote_inline(state: StateInline, silent: boolean): boolean { - const max = state.posMax; - const start = state.pos; - - if (start + 2 >= max) return false; - if (state.src.charCodeAt(start) !== 0x5E/* ^ */) return false; - if (state.src.charCodeAt(start + 1) !== 0x5B/* [ */) return false; - - const labelStart = start + 2; - const labelEnd = parseLinkLabel(state, start + 1); - - // parser failed to find ']', so it's not a valid note - if (labelEnd < 0) return false; - - // We found the end of the link, and know for a fact it's a valid link; - // so all that's left to do is to call tokenizer. - // - if (!silent) { - const env = state.env as FootnoteEnv; - if (!env.footnotes) env.footnotes = {}; - if (!env.footnotes.list) env.footnotes.list = []; - const footnoteId = env.footnotes.list.length; - const tokens: Token[] = []; - - state.md.inline.parse( - state.src.slice(labelStart, labelEnd), - state.md, - state.env, - tokens - ); - - const token = state.push('footnote_ref', '', 0); - token.meta = { id: footnoteId }; - - env.footnotes.list[footnoteId] = { - content: state.src.slice(labelStart, labelEnd), - tokens, - count: 0 - }; - } - - state.pos = labelEnd + 1; - state.posMax = max; - return true; - } - - // Process footnote references ([^...]) - function footnote_ref(state: StateInline, silent: boolean): boolean { - const max = state.posMax; - const start = state.pos; - - // should be at least 4 chars - "[^x]" - if (start + 3 > max) return false; - - const env = state.env as FootnoteEnv; - if (!env.footnotes || !env.footnotes.refs) return false; - if (state.src.charCodeAt(start) !== 0x5B/* [ */) return false; - if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) return false; - - let pos: number; - - for (pos = start + 2; pos < max; pos++) { - if (state.src.charCodeAt(pos) === 0x20) return false; - if (state.src.charCodeAt(pos) === 0x0A) return false; - if (state.src.charCodeAt(pos) === 0x5D /* ] */) { - break; - } - } - - if (pos === start + 2) return false; // no empty footnote labels - if (pos >= max) return false; - pos++; - - const label = state.src.slice(start + 2, pos - 1); - if (typeof env.footnotes.refs[`:${label}`] === 'undefined') return false; - - if (!silent) { - if (!env.footnotes.list) env.footnotes.list = []; - - let footnoteId: number; - - if (env.footnotes.refs[`:${label}`] < 0) { - footnoteId = env.footnotes.list.length; - env.footnotes.list[footnoteId] = { label, count: 0 }; - env.footnotes.refs[`:${label}`] = footnoteId; - } else { - footnoteId = env.footnotes.refs[`:${label}`]; - } - - const footnoteSubId = env.footnotes.list[footnoteId].count; - env.footnotes.list[footnoteId].count++; - - const token = state.push('footnote_ref', '', 0); - token.meta = { id: footnoteId, subId: footnoteSubId, label }; - } - - state.pos = pos; - state.posMax = max; - return true; - } - - // Glue footnote tokens to end of token stream - function footnote_tail(state: StateCore): void { - let tokens: Token[] | null = null; - let current: Token[]; - let currentLabel: string; - let insideRef = false; - const refTokens: { [key: string]: Token[] } = {}; - - const env = state.env as FootnoteEnv; - if (!env.footnotes) { return; } - - state.tokens = state.tokens.filter(function (tok) { - if (tok.type === 'footnote_reference_open') { - insideRef = true; - current = []; - currentLabel = tok.meta.label; - return false; - } - if (tok.type === 'footnote_reference_close') { - insideRef = false; - // prepend ':' to avoid conflict with Object.prototype members - refTokens[':' + currentLabel] = current; - return false; - } - if (insideRef) { current.push(tok); } - return !insideRef; - }); - - if (!env.footnotes.list) { return; } - const list = env.footnotes.list; - - state.tokens.push(new state.Token('footnote_block_open', '', 1)); - - for (let i = 0, l = list.length; i < l; i++) { - const token_fo = new state.Token('footnote_open', '', 1); - token_fo.meta = { id: i, label: list[i].label }; - state.tokens.push(token_fo); - - if (list[i].tokens) { - tokens = []; - - const token_po = new state.Token('paragraph_open', 'p', 1); - token_po.block = true; - tokens.push(token_po); - - const token_i = new state.Token('inline', '', 0); - token_i.children = list[i].tokens || null; - token_i.content = list[i].content || ''; - tokens.push(token_i); - - const token_pc = new state.Token('paragraph_close', 'p', -1); - token_pc.block = true; - tokens.push(token_pc); - } else if (list[i].label) { - tokens = refTokens[`:${list[i].label}`] || null; - } - - if (tokens) state.tokens = state.tokens.concat(tokens); - - let lastParagraph: Token | null; - - if (state.tokens[state.tokens.length - 1].type === 'paragraph_close') { - lastParagraph = state.tokens.pop()!; - } else { - lastParagraph = null; - } - - const t = list[i].count > 0 ? list[i].count : 1; - for (let j = 0; j < t; j++) { - const token_a = new state.Token('footnote_anchor', '', 0); - token_a.meta = { id: i, subId: j, label: list[i].label }; - state.tokens.push(token_a); - } - - if (lastParagraph) { - state.tokens.push(lastParagraph); - } - - state.tokens.push(new state.Token('footnote_close', '', -1)); - } - - state.tokens.push(new state.Token('footnote_block_close', '', -1)); - } - - md.block.ruler.before('reference', 'footnote_def', footnote_def, { alt: ['paragraph', 'reference'] }); - md.inline.ruler.after('image', 'footnote_inline', footnote_inline); - md.inline.ruler.after('footnote_inline', 'footnote_ref', footnote_ref); - md.core.ruler.after('inline', 'footnote_tail', footnote_tail); -} \ No newline at end of file diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-ins/index.ts b/frontend/src/common/markdown-it/plugins/markdown-it-ins/index.ts deleted file mode 100644 index 9521bde..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-ins/index.ts +++ /dev/null @@ -1,160 +0,0 @@ -import MarkdownIt, { StateInline, Token } from 'markdown-it'; - -/** - * 分隔符接口定义 - */ -interface Delimiter { - marker: number; - length: number; - jump: number; - token: number; - end: number; - open: boolean; - close: boolean; -} - -/** - * 扫描结果接口定义 - */ -interface ScanResult { - can_open: boolean; - can_close: boolean; - length: number; -} - -/** - * Token 元数据接口定义 - */ -interface TokenMeta { - delimiters?: Delimiter[]; -} - -/** - * markdown-it-ins 插件 - * 用于支持插入文本语法 ++text++ - */ -export default function ins_plugin(md: MarkdownIt): void { - // Insert each marker as a separate text token, and add it to delimiter list - // - function tokenize(state: StateInline, silent: boolean): boolean { - const start = state.pos; - const marker = state.src.charCodeAt(start); - - if (silent) { return false; } - - if (marker !== 0x2B/* + */) { return false; } - - const scanned = state.scanDelims(state.pos, true) as ScanResult; - let len = scanned.length; - const ch = String.fromCharCode(marker); - - if (len < 2) { return false; } - - if (len % 2) { - const token: Token = state.push('text', '', 0); - token.content = ch; - len--; - } - - for (let i = 0; i < len; i += 2) { - const token: Token = state.push('text', '', 0); - token.content = ch + ch; - - if (!scanned.can_open && !scanned.can_close) { continue; } - - state.delimiters.push({ - marker, - length: 0, // disable "rule of 3" length checks meant for emphasis - jump: i / 2, // 1 delimiter = 2 characters - token: state.tokens.length - 1, - end: -1, - open: scanned.can_open, - close: scanned.can_close - } as Delimiter); - } - - state.pos += scanned.length; - - return true; - } - - // Walk through delimiter list and replace text tokens with tags - // - function postProcess(state: StateInline, delimiters: Delimiter[]): void { - let token: Token; - const loneMarkers: number[] = []; - const max = delimiters.length; - - for (let i = 0; i < max; i++) { - const startDelim = delimiters[i]; - - if (startDelim.marker !== 0x2B/* + */) { - continue; - } - - if (startDelim.end === -1) { - continue; - } - - const endDelim = delimiters[startDelim.end]; - - token = state.tokens[startDelim.token]; - token.type = 'ins_open'; - token.tag = 'ins'; - token.nesting = 1; - token.markup = '++'; - token.content = ''; - - token = state.tokens[endDelim.token]; - token.type = 'ins_close'; - token.tag = 'ins'; - token.nesting = -1; - token.markup = '++'; - token.content = ''; - - if (state.tokens[endDelim.token - 1].type === 'text' && - state.tokens[endDelim.token - 1].content === '+') { - loneMarkers.push(endDelim.token - 1); - } - } - - // If a marker sequence has an odd number of characters, it's splitted - // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the - // start of the sequence. - // - // So, we have to move all those markers after subsequent s_close tags. - // - while (loneMarkers.length) { - const i = loneMarkers.pop()!; - let j = i + 1; - - while (j < state.tokens.length && state.tokens[j].type === 'ins_close') { - j++; - } - - j--; - - if (i !== j) { - token = state.tokens[j]; - state.tokens[j] = state.tokens[i]; - state.tokens[i] = token; - } - } - } - - md.inline.ruler.before('emphasis', 'ins', tokenize); - md.inline.ruler2.before('emphasis', 'ins', function (state: StateInline): boolean { - const tokens_meta = state.tokens_meta as TokenMeta[]; - const max = (state.tokens_meta || []).length; - - postProcess(state, state.delimiters as Delimiter[]); - - for (let curr = 0; curr < max; curr++) { - if (tokens_meta[curr] && tokens_meta[curr].delimiters) { - postProcess(state, tokens_meta[curr].delimiters!); - } - } - - return true; - }); -} \ No newline at end of file diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-mark/index.ts b/frontend/src/common/markdown-it/plugins/markdown-it-mark/index.ts deleted file mode 100644 index ed18705..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-mark/index.ts +++ /dev/null @@ -1,160 +0,0 @@ -import MarkdownIt, {StateInline, Token} from 'markdown-it'; - -/** - * 分隔符接口定义 - */ -interface Delimiter { - marker: number; - length: number; - jump: number; - token: number; - end: number; - open: boolean; - close: boolean; -} - -/** - * 扫描结果接口定义 - */ -interface ScanResult { - can_open: boolean; - can_close: boolean; - length: number; -} - -/** - * Token 元数据接口定义 - */ -interface TokenMeta { - delimiters?: Delimiter[]; -} - -/** - * markdown-it-mark 插件 - * 用于支持 ==标记文本== 语法 - */ -export default function markPlugin(md: MarkdownIt): void { - // Insert each marker as a separate text token, and add it to delimiter list - // - function tokenize(state: StateInline, silent: boolean): boolean { - const start = state.pos; - const marker = state.src.charCodeAt(start); - - if (silent) { return false; } - - if (marker !== 0x3D/* = */) { return false; } - - const scanned = state.scanDelims(state.pos, true) as ScanResult; - let len = scanned.length; - const ch = String.fromCharCode(marker); - - if (len < 2) { return false; } - - if (len % 2) { - const token: Token = state.push('text', '', 0); - token.content = ch; - len--; - } - - for (let i = 0; i < len; i += 2) { - const token: Token = state.push('text', '', 0); - token.content = ch + ch; - - if (!scanned.can_open && !scanned.can_close) { continue; } - - state.delimiters.push({ - marker, - length: 0, // disable "rule of 3" length checks meant for emphasis - jump: i / 2, // 1 delimiter = 2 characters - token: state.tokens.length - 1, - end: -1, - open: scanned.can_open, - close: scanned.can_close - } as Delimiter); - } - - state.pos += scanned.length; - - return true; - } - - // Walk through delimiter list and replace text tokens with tags - // - function postProcess(state: StateInline, delimiters: Delimiter[]): void { - const loneMarkers: number[] = []; - const max = delimiters.length; - - for (let i = 0; i < max; i++) { - const startDelim = delimiters[i]; - - if (startDelim.marker !== 0x3D/* = */) { - continue; - } - - if (startDelim.end === -1) { - continue; - } - - const endDelim = delimiters[startDelim.end]; - - const token_o = state.tokens[startDelim.token]; - token_o.type = 'mark_open'; - token_o.tag = 'mark'; - token_o.nesting = 1; - token_o.markup = '=='; - token_o.content = ''; - - const token_c = state.tokens[endDelim.token]; - token_c.type = 'mark_close'; - token_c.tag = 'mark'; - token_c.nesting = -1; - token_c.markup = '=='; - token_c.content = ''; - - if (state.tokens[endDelim.token - 1].type === 'text' && - state.tokens[endDelim.token - 1].content === '=') { - loneMarkers.push(endDelim.token - 1); - } - } - - // If a marker sequence has an odd number of characters, it's splitted - // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the - // start of the sequence. - // - // So, we have to move all those markers after subsequent s_close tags. - // - while (loneMarkers.length) { - const i = loneMarkers.pop()!; - let j = i + 1; - - while (j < state.tokens.length && state.tokens[j].type === 'mark_close') { - j++; - } - - j--; - - if (i !== j) { - const token = state.tokens[j]; - state.tokens[j] = state.tokens[i]; - state.tokens[i] = token; - } - } - } - - md.inline.ruler.before('emphasis', 'mark', tokenize); - md.inline.ruler2.before('emphasis', 'mark', function (state: StateInline): boolean { - let curr: number; - const tokens_meta = state.tokens_meta as TokenMeta[]; - const max = (state.tokens_meta || []).length; - - postProcess(state, state.delimiters as Delimiter[]); - - for (curr = 0; curr < max; curr++) { - if (tokens_meta[curr] && tokens_meta[curr].delimiters) { - postProcess(state, tokens_meta[curr].delimiters!); - } - } - - return true; - }); -} \ No newline at end of file diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-mermaid/index.ts b/frontend/src/common/markdown-it/plugins/markdown-it-mermaid/index.ts deleted file mode 100644 index 734383d..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-mermaid/index.ts +++ /dev/null @@ -1,106 +0,0 @@ -import mermaid from "mermaid"; -import {genUid, hashCode, sleep} from "./utils"; - -const mermaidCache = new Map(); - -// 缓存计数器,用于清除缓存 -const mermaidCacheCount = new Map(); -let count = 0; - - -let countTmo = setTimeout(() => undefined, 0); -const addCount = () => { - clearTimeout(countTmo); - countTmo = setTimeout(() => { - count++; - clearCache(); - }, 500); -}; - -const clearCache = () => { - for (const key of mermaidCacheCount.keys()) { - const value = mermaidCacheCount.get(key)!; - if (value + 3 < count) { - mermaidCache.delete(key); - mermaidCacheCount.delete(key); - } - } -}; - -/** - * 渲染 mermaid - * @param code mermaid 代码 - * @param targetId 目标 id - * @param count 计数器 - */ -const renderMermaid = async (code: string, targetId: string, count: number) => { - let limit = 100; - while (limit-- > 0) { - const container = document.getElementById(targetId); - if (!container) { - await sleep(100); - continue; - } - try { - const {svg} = await mermaid.render("mermaid-svg-" + genUid(), code, container); - container.innerHTML = svg; - mermaidCache.set(targetId, container); - mermaidCacheCount.set(targetId, count); - } catch (e) { - } - break; - } -}; - -export interface MermaidItOptions { - theme?: "default" | "dark" | "forest" | "neutral" | "base"; -} - -/** - * 更新 mermaid 主题 - */ -export const updateMermaidTheme = (theme: "default" | "dark" | "forest" | "neutral" | "base") => { - mermaid.initialize({ - startOnLoad: false, - theme: theme - }); - // 清空缓存,强制重新渲染 - mermaidCache.clear(); - mermaidCacheCount.clear(); - -}; - -/** - * mermaid 插件 - * @param md markdown-it - * @param options 配置选项 - * @constructor MermaidIt - */ -export const MermaidIt = function (md: any, options?: MermaidItOptions): void { - const theme = options?.theme || "default"; - mermaid.initialize({ - startOnLoad: false, - theme: theme - }); - const defaultRenderer = md.renderer.rules.fence.bind(md.renderer.rules); - md.renderer.rules.fence = (tokens: any, idx: any, options: any, env: any, self: any) => { - addCount(); - const token = tokens[idx]; - const info = token.info.trim(); - if (info === "mermaid") { - const containerId = "mermaid-container-" + hashCode(token.content); - const container = document.createElement("div"); - container.id = containerId; - if (mermaidCache.has(containerId)) { - container.innerHTML = mermaidCache.get(containerId)!.innerHTML; - mermaidCacheCount.set(containerId, count); - } else { - renderMermaid(token.content, containerId, count).then(); - } - return container.outerHTML; - } - // 使用默认的渲染规则 - return defaultRenderer(tokens, idx, options, env, self); - }; -}; - diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-mermaid/utils.ts b/frontend/src/common/markdown-it/plugins/markdown-it-mermaid/utils.ts deleted file mode 100644 index f3c4486..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-mermaid/utils.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { v4 as uuidv4 } from "uuid"; - -/** - * uuid 生成函数 - * @param split 分隔符 - */ -export const genUid = (split = "") => { - return uuidv4().split("-").join(split); -}; - -/** - * 一个简易的sleep函数 - */ -export const sleep = async (ms: number) => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); -}; - -/** - * 计算字符串的hash值 - * 返回一个数字 - * @param str - */ -export const hashCode = (str: string) => { - let hash = 0; - if (str.length === 0) return hash; - for (let i = 0; i < str.length; i++) { - const char = str.charCodeAt(i); - hash = (hash << 5) - hash + char; - hash = hash & hash; // Convert to 32bit integer - } - return hash; -}; - -/** - * 一个简易的阻塞函数 - */ -export const awaitFor = async (cb: () => boolean, timeout = 0, errText = "超时暂停阻塞") => { - const start = Date.now(); - while (true) { - if (cb()) return true; - if (timeout && Date.now() - start > timeout) { - console.error("阻塞超时: " + errText); - return false; - } - await sleep(100); - } -}; diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-sub/index.ts b/frontend/src/common/markdown-it/plugins/markdown-it-sub/index.ts deleted file mode 100644 index f2e00cf..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-sub/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -// Process ~subscript~ - -import MarkdownIt, { StateInline, Token } from 'markdown-it'; - -// same as UNESCAPE_MD_RE plus a space -const UNESCAPE_RE = /\\([ \\!"#$%&'()*+,./:;<=>?@[\]^_`{|}~-])/g; - -function subscript(state: StateInline, silent: boolean): boolean { - const max = state.posMax; - const start = state.pos; - - if (state.src.charCodeAt(start) !== 0x7E/* ~ */) { return false; } - if (silent) { return false; } // don't run any pairs in validation mode - if (start + 2 >= max) { return false; } - - state.pos = start + 1; - let found = false; - - while (state.pos < max) { - if (state.src.charCodeAt(state.pos) === 0x7E/* ~ */) { - found = true; - break; - } - - state.md.inline.skipToken(state); - } - - if (!found || start + 1 === state.pos) { - state.pos = start; - return false; - } - - const content = state.src.slice(start + 1, state.pos); - - // don't allow unescaped spaces/newlines inside - if (content.match(/(^|[^\\])(\\\\)*\s/)) { - state.pos = start; - return false; - } - - // found! - state.posMax = state.pos; - state.pos = start + 1; - - // Earlier we checked !silent, but this implementation does not need it - const token_so: Token = state.push('sub_open', 'sub', 1); - token_so.markup = '~'; - - const token_t: Token = state.push('text', '', 0); - token_t.content = content.replace(UNESCAPE_RE, '$1'); - - const token_sc: Token = state.push('sub_close', 'sub', -1); - token_sc.markup = '~'; - - state.pos = state.posMax + 1; - state.posMax = max; - return true; -} - -/** - * markdown-it-sub 插件 - * 用于支持下标语法 ~text~ - */ -export default function sub_plugin(md: MarkdownIt): void { - md.inline.ruler.after('emphasis', 'sub', subscript); -} \ No newline at end of file diff --git a/frontend/src/common/markdown-it/plugins/markdown-it-sup/index.ts b/frontend/src/common/markdown-it/plugins/markdown-it-sup/index.ts deleted file mode 100644 index eb5c8cd..0000000 --- a/frontend/src/common/markdown-it/plugins/markdown-it-sup/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -// Process ^superscript^ - -import MarkdownIt, { StateInline, Token } from 'markdown-it'; - -// same as UNESCAPE_MD_RE plus a space -const UNESCAPE_RE = /\\([ \\!"#$%&'()*+,./:;<=>?@[\]^_`{|}~-])/g; - -function superscript(state: StateInline, silent: boolean): boolean { - const max = state.posMax; - const start = state.pos; - - if (state.src.charCodeAt(start) !== 0x5E/* ^ */) { return false; } - if (silent) { return false; } // don't run any pairs in validation mode - if (start + 2 >= max) { return false; } - - state.pos = start + 1; - let found = false; - - while (state.pos < max) { - if (state.src.charCodeAt(state.pos) === 0x5E/* ^ */) { - found = true; - break; - } - - state.md.inline.skipToken(state); - } - - if (!found || start + 1 === state.pos) { - state.pos = start; - return false; - } - - const content = state.src.slice(start + 1, state.pos); - - // don't allow unescaped spaces/newlines inside - if (content.match(/(^|[^\\])(\\\\)*\s/)) { - state.pos = start; - return false; - } - - // found! - state.posMax = state.pos; - state.pos = start + 1; - - // Earlier we checked !silent, but this implementation does not need it - const token_so: Token = state.push('sup_open', 'sup', 1); - token_so.markup = '^'; - - const token_t: Token = state.push('text', '', 0); - token_t.content = content.replace(UNESCAPE_RE, '$1'); - - const token_sc: Token = state.push('sup_close', 'sup', -1); - token_sc.markup = '^'; - - state.pos = state.posMax + 1; - state.posMax = max; - return true; -} - -/** - * markdown-it-sup 插件 - * 用于支持上标语法 ^text^ - */ -export default function sup_plugin(md: MarkdownIt): void { - md.inline.ruler.after('emphasis', 'sup', superscript); -} \ No newline at end of file diff --git a/frontend/src/stores/themeStore.ts b/frontend/src/stores/themeStore.ts index 55787ef..6aba44e 100644 --- a/frontend/src/stores/themeStore.ts +++ b/frontend/src/stores/themeStore.ts @@ -6,6 +6,7 @@ import { useConfigStore } from './configStore'; import { useEditorStore } from './editorStore'; import type { ThemeColors } from '@/views/editor/theme/types'; import { cloneThemeColors, FALLBACK_THEME_NAME, themePresetList, themePresetMap } from '@/views/editor/theme/presets'; +import { refreshMermaidTheme } from '@/views/editor/extensions/markdown/plugins/mermaid'; type ThemeOption = { name: string; type: ThemeType }; @@ -139,6 +140,9 @@ export const useThemeStore = defineStore('theme', () => { const refreshEditorTheme = () => { applyThemeToDOM(currentTheme.value); + // Refresh mermaid diagrams with new theme + refreshMermaidTheme(); + const editorStore = useEditorStore(); editorStore?.applyThemeSettings(); }; diff --git a/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts b/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts index d92d63f..8e951c1 100644 --- a/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts +++ b/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts @@ -8,6 +8,8 @@ import {javascriptLanguage, typescriptLanguage} from "@codemirror/lang-javascrip import {html, htmlLanguage} from "@codemirror/lang-html"; import {StandardSQL} from "@codemirror/lang-sql"; import {markdown, markdownLanguage} from "@codemirror/lang-markdown"; +import {Subscript, Superscript} from "@lezer/markdown"; +import {Highlight} from "@/views/editor/extensions/markdown/syntax/highlight"; import {javaLanguage} from "@codemirror/lang-java"; import {phpLanguage} from "@codemirror/lang-php"; import {cssLanguage} from "@codemirror/lang-css"; @@ -113,7 +115,7 @@ export const LANGUAGES: LanguageInfo[] = [ }), new LanguageInfo("md", "Markdown", markdown({ base: markdownLanguage, - extensions: [], + extensions: [Subscript, Superscript, Highlight], completeHTMLTags: true, pasteURLAsLink: true, htmlTagLanguage: html({ diff --git a/frontend/src/views/editor/extensions/markdown/classes.ts b/frontend/src/views/editor/extensions/markdown/classes.ts index 152c67f..9d33d73 100644 --- a/frontend/src/views/editor/extensions/markdown/classes.ts +++ b/frontend/src/views/editor/extensions/markdown/classes.ts @@ -64,5 +64,14 @@ export const blockquote = { emoji = { /** Emoji widget */ widget: 'cm-emoji' + }, + /** Classes for mermaid diagram decorations. */ + mermaid = { + /** Mermaid preview container */ + preview: 'cm-mermaid-preview', + /** Loading state */ + loading: 'cm-mermaid-loading', + /** Error state */ + error: 'cm-mermaid-error' } diff --git a/frontend/src/views/editor/extensions/markdown/index.ts b/frontend/src/views/editor/extensions/markdown/index.ts index fc46a97..dfab0a2 100644 --- a/frontend/src/views/editor/extensions/markdown/index.ts +++ b/frontend/src/views/editor/extensions/markdown/index.ts @@ -12,6 +12,9 @@ import { codeblockEnhanced } from './plugins/code-block-enhanced'; import { emoji } from './plugins/emoji'; import { horizontalRule } from './plugins/horizontal-rule'; import { inlineCode } from './plugins/inline-code'; +import { subscriptSuperscript } from './plugins/subscript-superscript'; +import { highlight } from './plugins/highlight'; +import { mermaidPreview } from './plugins/mermaid'; /** @@ -32,6 +35,9 @@ export const markdownExtensions: Extension = [ emoji(), horizontalRule(), inlineCode(), + subscriptSuperscript(), + highlight(), + mermaidPreview(), ]; export default markdownExtensions; diff --git a/frontend/src/views/editor/extensions/markdown/plugins/emoji.ts b/frontend/src/views/editor/extensions/markdown/plugins/emoji.ts index e4c5b2e..5a48d4e 100644 --- a/frontend/src/views/editor/extensions/markdown/plugins/emoji.ts +++ b/frontend/src/views/editor/extensions/markdown/plugins/emoji.ts @@ -8,6 +8,7 @@ import { WidgetType } from '@codemirror/view'; import { isCursorInRange } from '../util'; +import { emojies } from '@/common/constant/emojies'; /** * Emoji plugin that converts :emoji_name: to actual emoji characters. @@ -17,133 +18,14 @@ import { isCursorInRange } from '../util'; * - Replaces them with actual emoji characters * - Shows the original text when cursor is nearby * - Uses RangeSetBuilder for optimal performance + * - Supports 1900+ emojis from the comprehensive emoji dictionary */ export const emoji = (): Extension => [emojiPlugin, baseTheme]; /** * Emoji regex pattern for matching :emoji_name: syntax. */ -const EMOJI_REGEX = /:([a-z0-9_+\-]+):/g; - -/** - * Common emoji mappings. - */ -const EMOJI_MAP: Map = new Map([ - // Smileys & Emotion - ['smile', '😄'], - ['smiley', '😃'], - ['grin', '😁'], - ['laughing', '😆'], - ['satisfied', '😆'], - ['sweat_smile', '😅'], - ['rofl', '🤣'], - ['joy', '😂'], - ['slightly_smiling_face', '🙂'], - ['upside_down_face', '🙃'], - ['wink', '😉'], - ['blush', '😊'], - ['innocent', '😇'], - ['smiling_face_with_three_hearts', '🥰'], - ['heart_eyes', '😍'], - ['star_struck', '🤩'], - ['kissing_heart', '😘'], - ['kissing', '😗'], - ['relaxed', '☺️'], - ['kissing_closed_eyes', '😚'], - ['kissing_smiling_eyes', '😙'], - ['smiling_face_with_tear', '🥲'], - ['yum', '😋'], - ['stuck_out_tongue', '😛'], - ['stuck_out_tongue_winking_eye', '😜'], - ['zany_face', '🤪'], - ['stuck_out_tongue_closed_eyes', '😝'], - ['money_mouth_face', '🤑'], - ['hugs', '🤗'], - ['hand_over_mouth', '🤭'], - ['shushing_face', '🤫'], - ['thinking', '🤔'], - ['zipper_mouth_face', '🤐'], - ['raised_eyebrow', '🤨'], - ['neutral_face', '😐'], - ['expressionless', '😑'], - ['no_mouth', '😶'], - ['smirk', '😏'], - ['unamused', '😒'], - ['roll_eyes', '🙄'], - ['grimacing', '😬'], - ['lying_face', '🤥'], - ['relieved', '😌'], - ['pensive', '😔'], - ['sleepy', '😪'], - ['drooling_face', '🤤'], - ['sleeping', '😴'], - - // Hearts - ['heart', '❤️'], - ['orange_heart', '🧡'], - ['yellow_heart', '💛'], - ['green_heart', '💚'], - ['blue_heart', '💙'], - ['purple_heart', '💜'], - ['brown_heart', '🤎'], - ['black_heart', '🖤'], - ['white_heart', '🤍'], - - // Gestures - ['+1', '👍'], - ['thumbsup', '👍'], - ['-1', '👎'], - ['thumbsdown', '👎'], - ['fist', '✊'], - ['facepunch', '👊'], - ['punch', '👊'], - ['wave', '👋'], - ['clap', '👏'], - ['raised_hands', '🙌'], - ['pray', '🙏'], - ['handshake', '🤝'], - - // Nature - ['sun', '☀️'], - ['moon', '🌙'], - ['star', '⭐'], - ['fire', '🔥'], - ['zap', '⚡'], - ['sparkles', '✨'], - ['tada', '🎉'], - ['rocket', '🚀'], - ['trophy', '🏆'], - - // Symbols - ['check', '✔️'], - ['x', '❌'], - ['warning', '⚠️'], - ['bulb', '💡'], - ['question', '❓'], - ['exclamation', '❗'], - ['heavy_check_mark', '✔️'], - - // Common - ['eyes', '👀'], - ['eye', '👁️'], - ['brain', '🧠'], - ['muscle', '💪'], - ['ok_hand', '👌'], - ['point_right', '👉'], - ['point_left', '👈'], - ['point_up', '☝️'], - ['point_down', '👇'], -]); - -/** - * Reverse lookup map for emoji to name. - */ -const EMOJI_REVERSE_MAP = new Map(); -EMOJI_MAP.forEach((emoji, name) => { - if (!EMOJI_REVERSE_MAP.has(emoji)) { - EMOJI_REVERSE_MAP.set(emoji, name); - } -}); +const EMOJI_REGEX = /:([a-z0-9_+\-]+):/gi; /** * Emoji widget with optimized rendering. @@ -190,8 +72,8 @@ function findEmojiMatches(text: string, offset: number): EmojiMatch[] { EMOJI_REGEX.lastIndex = 0; while ((match = EMOJI_REGEX.exec(text)) !== null) { - const name = match[1]; - const emoji = EMOJI_MAP.get(name); + const name = match[1].toLowerCase(); + const emoji = emojies[name]; if (emoji) { matches.push({ @@ -285,26 +167,16 @@ const baseTheme = EditorView.baseTheme({ } }); -/** - * Add custom emoji to the map. - * @param name - Emoji name (without colons) - * @param emoji - Emoji character - */ -export function addEmoji(name: string, emoji: string): void { - EMOJI_MAP.set(name, emoji); - EMOJI_REVERSE_MAP.set(emoji, name); -} - /** * Get all available emoji names. */ export function getEmojiNames(): string[] { - return Array.from(EMOJI_MAP.keys()); + return Object.keys(emojies); } /** * Get emoji by name. */ export function getEmoji(name: string): string | undefined { - return EMOJI_MAP.get(name); + return emojies[name.toLowerCase()]; } diff --git a/frontend/src/views/editor/extensions/markdown/plugins/highlight.ts b/frontend/src/views/editor/extensions/markdown/plugins/highlight.ts new file mode 100644 index 0000000..ca6b070 --- /dev/null +++ b/frontend/src/views/editor/extensions/markdown/plugins/highlight.ts @@ -0,0 +1,115 @@ +import { Extension, Range } from '@codemirror/state'; +import { syntaxTree } from '@codemirror/language'; +import { + ViewPlugin, + DecorationSet, + Decoration, + EditorView, + ViewUpdate +} from '@codemirror/view'; +import { isCursorInRange, invisibleDecoration } from '../util'; + +/** + * Highlight plugin using syntax tree. + * + * Uses the custom Highlight extension to detect: + * - Highlight: ==text== → renders as highlighted text + * + * Examples: + * - This is ==important== text → This is important text + * - Please ==review this section== carefully + */ +export const highlight = (): Extension => [ + highlightPlugin, + baseTheme +]; + +/** + * Build decorations for highlight using syntax tree. + */ +function buildDecorations(view: EditorView): DecorationSet { + const decorations: Range[] = []; + + for (const { from, to } of view.visibleRanges) { + syntaxTree(view.state).iterate({ + from, + to, + enter: ({ type, from: nodeFrom, to: nodeTo, node }) => { + // Handle Highlight nodes + if (type.name === 'Highlight') { + const cursorInRange = isCursorInRange(view.state, [nodeFrom, nodeTo]); + + // Get the mark nodes (the == characters) + const marks = node.getChildren('HighlightMark'); + + if (!cursorInRange && marks.length >= 2) { + // Hide the opening and closing == marks + decorations.push(invisibleDecoration.range(marks[0].from, marks[0].to)); + decorations.push(invisibleDecoration.range(marks[marks.length - 1].from, marks[marks.length - 1].to)); + + // Apply highlight style to the content between marks + const contentStart = marks[0].to; + const contentEnd = marks[marks.length - 1].from; + if (contentStart < contentEnd) { + decorations.push( + Decoration.mark({ + class: 'cm-highlight' + }).range(contentStart, contentEnd) + ); + } + } + } + } + }); + } + + return Decoration.set(decorations, true); +} + +/** + * Plugin class with optimized update detection. + */ +class HighlightPlugin { + decorations: DecorationSet; + private lastSelectionHead: number = -1; + + constructor(view: EditorView) { + this.decorations = buildDecorations(view); + this.lastSelectionHead = view.state.selection.main.head; + } + + update(update: ViewUpdate) { + if (update.docChanged || update.viewportChanged) { + this.decorations = buildDecorations(update.view); + this.lastSelectionHead = update.state.selection.main.head; + return; + } + + if (update.selectionSet) { + const newHead = update.state.selection.main.head; + if (newHead !== this.lastSelectionHead) { + this.decorations = buildDecorations(update.view); + this.lastSelectionHead = newHead; + } + } + } +} + +const highlightPlugin = ViewPlugin.fromClass( + HighlightPlugin, + { + decorations: (v) => v.decorations + } +); + +/** + * Base theme for highlight. + * Uses mark decoration with a subtle background color. + */ +const baseTheme = EditorView.baseTheme({ + '.cm-highlight': { + backgroundColor: 'var(--cm-highlight-background, rgba(255, 235, 59, 0.4))', + borderRadius: '2px', + } +}); + diff --git a/frontend/src/views/editor/extensions/markdown/plugins/html.ts b/frontend/src/views/editor/extensions/markdown/plugins/html.ts index f11e3d7..d270678 100644 --- a/frontend/src/views/editor/extensions/markdown/plugins/html.ts +++ b/frontend/src/views/editor/extensions/markdown/plugins/html.ts @@ -1,9 +1,11 @@ import { syntaxTree } from '@codemirror/language'; -import { EditorState, StateField, Range } from '@codemirror/state'; +import { EditorState, Range } from '@codemirror/state'; import { Decoration, DecorationSet, EditorView, + ViewPlugin, + ViewUpdate, WidgetType } from '@codemirror/view'; import DOMPurify from 'dompurify'; @@ -15,34 +17,41 @@ interface EmbedBlockData { content: string; } -function extractHTMLBlocks(state: EditorState) { +/** + * Extract all HTML blocks from the document (both HTMLBlock and HTMLTag). + * Returns all blocks regardless of cursor position. + */ +function extractAllHTMLBlocks(state: EditorState): EmbedBlockData[] { const blocks = new Array(); syntaxTree(state).iterate({ enter({ from, to, name }) { - if (name !== 'HTMLBlock') return; - if (isCursorInRange(state, [from, to])) return; + // Support both block-level HTML (HTMLBlock) and inline HTML tags (HTMLTag) + if (name !== 'HTMLBlock' && name !== 'HTMLTag') return; const html = state.sliceDoc(from, to); const content = DOMPurify.sanitize(html); - blocks.push({ - from, - to, - content - }); + // Skip empty content after sanitization + if (!content.trim()) return; + + blocks.push({ from, to, content }); } }); return blocks; } -// Decoration to hide the original HTML source code -const hideDecoration = Decoration.replace({}); - -function blockToDecoration(blocks: EmbedBlockData[]): Range[] { +/** + * Build decorations for HTML blocks. + * Only shows preview for blocks where cursor is not inside. + */ +function buildDecorations(state: EditorState, blocks: EmbedBlockData[]): DecorationSet { const decorations: Range[] = []; for (const block of blocks) { + // Skip if cursor is in range + if (isCursorInRange(state, [block.from, block.to])) continue; + // Hide the original HTML source code - decorations.push(hideDecoration.range(block.from, block.to)); + decorations.push(Decoration.replace({}).range(block.from, block.to)); // Add the preview widget at the end decorations.push( @@ -53,25 +62,57 @@ function blockToDecoration(blocks: EmbedBlockData[]): Range[] { ); } - return decorations; + return Decoration.set(decorations, true); } -export const htmlBlock = StateField.define({ - create(state) { - return Decoration.set(blockToDecoration(extractHTMLBlocks(state)), true); - }, - update(value, tx) { - if (tx.docChanged || tx.selection) { - return Decoration.set( - blockToDecoration(extractHTMLBlocks(tx.state)), - true - ); - } - return value.map(tx.changes); - }, - provide(field) { - return EditorView.decorations.from(field); +/** + * Check if selection affects any HTML block (cursor moved in/out of a block). + */ +function selectionAffectsBlocks( + state: EditorState, + prevState: EditorState, + blocks: EmbedBlockData[] +): boolean { + for (const block of blocks) { + const wasInRange = isCursorInRange(prevState, [block.from, block.to]); + const isInRange = isCursorInRange(state, [block.from, block.to]); + if (wasInRange !== isInRange) return true; } + return false; +} + +/** + * ViewPlugin for HTML block preview. + * Uses smart caching to avoid unnecessary updates during text selection. + */ +class HTMLBlockPlugin { + decorations: DecorationSet; + blocks: EmbedBlockData[]; + + constructor(view: EditorView) { + this.blocks = extractAllHTMLBlocks(view.state); + this.decorations = buildDecorations(view.state, this.blocks); + } + + update(update: ViewUpdate) { + // If document changed, re-extract all blocks + if (update.docChanged) { + this.blocks = extractAllHTMLBlocks(update.state); + this.decorations = buildDecorations(update.state, this.blocks); + return; + } + + // If selection changed, only rebuild if cursor moved in/out of a block + if (update.selectionSet) { + if (selectionAffectsBlocks(update.state, update.startState, this.blocks)) { + this.decorations = buildDecorations(update.state, this.blocks); + } + } + } +} + +const htmlBlockPlugin = ViewPlugin.fromClass(HTMLBlockPlugin, { + decorations: (v) => v.decorations }); class HTMLBlockWidget extends WidgetType { @@ -123,12 +164,19 @@ class HTMLBlockWidget extends WidgetType { */ const baseTheme = EditorView.baseTheme({ '.cm-html-block-widget': { - display: 'block', + display: 'inline-block', position: 'relative', - width: '100%', - overflow: 'auto' + maxWidth: '100%', + overflow: 'auto', + verticalAlign: 'middle' }, '.cm-html-block-content': { + display: 'inline-block' + }, + // Ensure images are properly sized + '.cm-html-block-content img': { + maxWidth: '100%', + height: 'auto', display: 'block' }, '.cm-html-block-edit-btn': { @@ -157,4 +205,4 @@ const baseTheme = EditorView.baseTheme({ }); // Export the extension with theme -export const htmlBlockExtension = [htmlBlock, baseTheme]; +export const htmlBlockExtension = [htmlBlockPlugin, baseTheme]; diff --git a/frontend/src/views/editor/extensions/markdown/plugins/mermaid.ts b/frontend/src/views/editor/extensions/markdown/plugins/mermaid.ts new file mode 100644 index 0000000..a41c189 --- /dev/null +++ b/frontend/src/views/editor/extensions/markdown/plugins/mermaid.ts @@ -0,0 +1,402 @@ +import { Extension, Range } from '@codemirror/state'; +import { syntaxTree } from '@codemirror/language'; +import { + ViewPlugin, + DecorationSet, + Decoration, + EditorView, + ViewUpdate, + WidgetType +} from '@codemirror/view'; +import { isCursorInRange } from '../util'; +import mermaid from 'mermaid'; + +/** + * Mermaid diagram preview plugin. + * + * This plugin detects mermaid code blocks and renders them as SVG diagrams. + * Features: + * - Detects ```mermaid code blocks + * - Renders mermaid diagrams as inline SVG + * - Shows the original code when cursor is in the block + * - Caches rendered diagrams for performance + * - Supports theme switching (dark/light) + * - Supports all mermaid diagram types (flowchart, sequence, etc.) + */ +export const mermaidPreview = (): Extension => [ + mermaidPlugin, + baseTheme +]; + +// Current mermaid theme +let currentMermaidTheme: 'default' | 'dark' = 'default'; +let mermaidInitialized = false; + +/** + * Detect the current theme from the DOM. + */ +function detectTheme(): 'default' | 'dark' { + const dataTheme = document.documentElement.getAttribute('data-theme'); + + if (dataTheme === 'light') { + return 'default'; + } + + if (dataTheme === 'dark') { + return 'dark'; + } + + // For 'auto', check system preference + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'dark'; + } + + return 'default'; +} + +/** + * Initialize mermaid with the specified theme. + */ +function initMermaid(theme: 'default' | 'dark' = currentMermaidTheme) { + mermaid.initialize({ + startOnLoad: false, + theme, + securityLevel: 'strict', + flowchart: { + htmlLabels: true, + curve: 'basis' + }, + sequence: { + showSequenceNumbers: false + }, + logLevel: 'error' + }); + + currentMermaidTheme = theme; + mermaidInitialized = true; +} + +/** + * Information about a mermaid code block. + */ +interface MermaidBlockInfo { + /** Start position of the code block */ + from: number; + /** End position of the code block */ + to: number; + /** The mermaid code content */ + code: string; + /** Unique ID for rendering */ + id: string; +} + +/** + * Cache for rendered mermaid diagrams. + * Key is `${theme}:${code}` to support theme-specific caching. + */ +const renderCache = new Map(); + +/** + * Generate cache key for a diagram. + */ +function getCacheKey(code: string): string { + return `${currentMermaidTheme}:${code}`; +} + +/** + * Generate a unique ID for a mermaid diagram. + */ +let idCounter = 0; +function generateId(): string { + return `mermaid-${Date.now()}-${idCounter++}`; +} + +/** + * Extract mermaid code blocks from the visible ranges. + */ +function extractMermaidBlocks(view: EditorView): MermaidBlockInfo[] { + const blocks: MermaidBlockInfo[] = []; + + for (const { from, to } of view.visibleRanges) { + syntaxTree(view.state).iterate({ + from, + to, + enter: (node) => { + if (node.name !== 'FencedCode') return; + + // Check if this is a mermaid code block + const codeInfoNode = node.node.getChild('CodeInfo'); + if (!codeInfoNode) return; + + const language = view.state.doc + .sliceString(codeInfoNode.from, codeInfoNode.to) + .trim() + .toLowerCase(); + + if (language !== 'mermaid') return; + + // Extract the code content + const firstLine = view.state.doc.lineAt(node.from); + const lastLine = view.state.doc.lineAt(node.to); + const codeStart = firstLine.to + 1; + const codeEnd = lastLine.from - 1; + + if (codeStart >= codeEnd) return; + + const code = view.state.doc.sliceString(codeStart, codeEnd).trim(); + + if (code) { + blocks.push({ + from: node.from, + to: node.to, + code, + id: generateId() + }); + } + } + }); + } + + return blocks; +} + +/** + * Mermaid preview widget that renders the diagram. + */ +class MermaidPreviewWidget extends WidgetType { + private svg: string | null = null; + private error: string | null = null; + private rendering = false; + + constructor( + readonly code: string, + readonly blockId: string + ) { + super(); + // Check cache first (theme-specific) + const cached = renderCache.get(getCacheKey(code)); + if (cached) { + this.svg = cached; + } + } + + eq(other: MermaidPreviewWidget): boolean { + return other.code === this.code; + } + + toDOM(view: EditorView): HTMLElement { + const container = document.createElement('div'); + container.className = 'cm-mermaid-preview'; + + if (this.svg) { + // Use cached SVG + container.innerHTML = this.svg; + this.setupSvgStyles(container); + } else if (this.error) { + // Show error + const errorEl = document.createElement('div'); + errorEl.className = 'cm-mermaid-error'; + errorEl.textContent = `Mermaid Error: ${this.error}`; + container.appendChild(errorEl); + } else { + // Show loading and start rendering + const loading = document.createElement('div'); + loading.className = 'cm-mermaid-loading'; + loading.textContent = 'Rendering diagram...'; + container.appendChild(loading); + + // Render asynchronously + if (!this.rendering) { + this.rendering = true; + this.renderMermaid(container, view); + } + } + + return container; + } + + private async renderMermaid(container: HTMLElement, view: EditorView) { + // Ensure mermaid is initialized with current theme + const theme = detectTheme(); + if (!mermaidInitialized || currentMermaidTheme !== theme) { + initMermaid(theme); + } + + try { + const { svg } = await mermaid.render(this.blockId, this.code); + + // Cache the result with theme-specific key + renderCache.set(getCacheKey(this.code), svg); + this.svg = svg; + + // Update the container + container.innerHTML = svg; + container.classList.remove('cm-mermaid-loading'); + this.setupSvgStyles(container); + + // Trigger a re-render to update decorations + view.dispatch({}); + } catch (err) { + this.error = err instanceof Error ? err.message : String(err); + + // Clear the loading state and show error + container.innerHTML = ''; + const errorEl = document.createElement('div'); + errorEl.className = 'cm-mermaid-error'; + errorEl.textContent = `Mermaid Error: ${this.error}`; + container.appendChild(errorEl); + } + } + + private setupSvgStyles(container: HTMLElement) { + const svg = container.querySelector('svg'); + if (svg) { + svg.style.maxWidth = '100%'; + svg.style.height = 'auto'; + svg.removeAttribute('height'); + } + } + + ignoreEvent(): boolean { + return true; + } +} + +/** + * Build decorations for mermaid code blocks. + */ +function buildMermaidDecorations(view: EditorView): DecorationSet { + const decorations: Range[] = []; + const blocks = extractMermaidBlocks(view); + + for (const block of blocks) { + // Skip if cursor is in this code block + if (isCursorInRange(view.state, [block.from, block.to])) { + continue; + } + + // Add preview widget after the code block + decorations.push( + Decoration.widget({ + widget: new MermaidPreviewWidget(block.code, block.id), + side: 1 + }).range(block.to) + ); + } + + return Decoration.set(decorations, true); +} + +/** + * Track the last known theme for change detection. + */ +let lastTheme: 'default' | 'dark' = detectTheme(); + +/** + * Mermaid preview plugin class. + */ +class MermaidPreviewPlugin { + decorations: DecorationSet; + private lastSelectionHead: number = -1; + + constructor(view: EditorView) { + // Initialize mermaid with detected theme + lastTheme = detectTheme(); + initMermaid(lastTheme); + this.decorations = buildMermaidDecorations(view); + this.lastSelectionHead = view.state.selection.main.head; + } + + update(update: ViewUpdate) { + // Check if theme changed + const currentTheme = detectTheme(); + if (currentTheme !== lastTheme) { + lastTheme = currentTheme; + // Theme changed, clear cache and reinitialize + renderCache.clear(); + initMermaid(currentTheme); + this.decorations = buildMermaidDecorations(update.view); + this.lastSelectionHead = update.state.selection.main.head; + return; + } + + if (update.docChanged || update.viewportChanged) { + this.decorations = buildMermaidDecorations(update.view); + this.lastSelectionHead = update.state.selection.main.head; + return; + } + + if (update.selectionSet) { + const newHead = update.state.selection.main.head; + if (newHead !== this.lastSelectionHead) { + this.decorations = buildMermaidDecorations(update.view); + this.lastSelectionHead = newHead; + } + } + } +} + +const mermaidPlugin = ViewPlugin.fromClass(MermaidPreviewPlugin, { + decorations: (v) => v.decorations +}); + +/** + * Base theme for mermaid preview. + */ +const baseTheme = EditorView.baseTheme({ + '.cm-mermaid-preview': { + display: 'block', + backgroundColor: 'var(--cm-mermaid-bg, rgba(128, 128, 128, 0.05))', + borderRadius: '0.5rem', + overflow: 'auto', + textAlign: 'center' + }, + '.cm-mermaid-preview svg': { + maxWidth: '100%', + height: 'auto' + }, + '.cm-mermaid-loading': { + color: 'var(--cm-foreground)', + opacity: '0.6', + fontStyle: 'italic', + }, + '.cm-mermaid-error': { + color: 'var(--cm-error, #ef4444)', + backgroundColor: 'var(--cm-error-bg, rgba(239, 68, 68, 0.1))', + borderRadius: '0.25rem', + fontSize: '0.875rem', + textAlign: 'left', + fontFamily: 'var(--voidraft-font-mono)', + whiteSpace: 'pre-wrap', + wordBreak: 'break-word' + } +}); + +/** + * Clear the mermaid render cache. + * Call this when theme changes to re-render diagrams. + */ +export function clearMermaidCache(): void { + renderCache.clear(); +} + +/** + * Update mermaid theme based on current system theme. + * Call this when the application theme changes. + */ +export function refreshMermaidTheme(): void { + const theme = detectTheme(); + if (theme !== currentMermaidTheme) { + renderCache.clear(); + initMermaid(theme); + } +} + +/** + * Force refresh all mermaid diagrams. + * Clears cache and reinitializes with current theme. + */ +export function forceRefreshMermaid(): void { + renderCache.clear(); + initMermaid(detectTheme()); +} diff --git a/frontend/src/views/editor/extensions/markdown/plugins/subscript-superscript.ts b/frontend/src/views/editor/extensions/markdown/plugins/subscript-superscript.ts new file mode 100644 index 0000000..3ce9d65 --- /dev/null +++ b/frontend/src/views/editor/extensions/markdown/plugins/subscript-superscript.ts @@ -0,0 +1,163 @@ +import { Extension, Range } from '@codemirror/state'; +import { syntaxTree } from '@codemirror/language'; +import { + ViewPlugin, + DecorationSet, + Decoration, + EditorView, + ViewUpdate +} from '@codemirror/view'; +import { isCursorInRange, invisibleDecoration } from '../util'; + +/** + * Subscript and Superscript plugin using syntax tree. + * + * Uses lezer-markdown's Subscript and Superscript extensions to detect: + * - Superscript: ^text^ → renders as superscript + * - Subscript: ~text~ → renders as subscript + * + * Examples: + * - 19^th^ → 19ᵗʰ (superscript) + * - H~2~O → H₂O (subscript) + */ +export const subscriptSuperscript = (): Extension => [ + subscriptSuperscriptPlugin, + baseTheme +]; + +/** + * Build decorations for subscript and superscript using syntax tree. + */ +function buildDecorations(view: EditorView): DecorationSet { + const decorations: Range[] = []; + + for (const { from, to } of view.visibleRanges) { + syntaxTree(view.state).iterate({ + from, + to, + enter: ({ type, from: nodeFrom, to: nodeTo, node }) => { + // Handle Superscript nodes + if (type.name === 'Superscript') { + // Get the full content including marks + const fullContent = view.state.doc.sliceString(nodeFrom, nodeTo); + + // Skip if this contains inline footnote pattern ^[ + // This catches ^[text] being misinterpreted as superscript + if (fullContent.includes('^[') || fullContent.includes('[') && fullContent.includes(']')) { + return; + } + + const cursorInRange = isCursorInRange(view.state, [nodeFrom, nodeTo]); + + // Get the mark nodes (the ^ characters) + const marks = node.getChildren('SuperscriptMark'); + + if (!cursorInRange && marks.length >= 2) { + // Get inner content between marks + const innerContent = view.state.doc.sliceString(marks[0].to, marks[marks.length - 1].from); + + // Skip if inner content looks like footnote (starts with [ or contains brackets) + if (innerContent.startsWith('[') || innerContent.includes('[') || innerContent.includes(']')) { + return; + } + + // Hide the opening and closing ^ marks + decorations.push(invisibleDecoration.range(marks[0].from, marks[0].to)); + decorations.push(invisibleDecoration.range(marks[marks.length - 1].from, marks[marks.length - 1].to)); + + // Apply superscript style to the content between marks + const contentStart = marks[0].to; + const contentEnd = marks[marks.length - 1].from; + if (contentStart < contentEnd) { + decorations.push( + Decoration.mark({ + class: 'cm-superscript' + }).range(contentStart, contentEnd) + ); + } + } + } + + // Handle Subscript nodes + if (type.name === 'Subscript') { + const cursorInRange = isCursorInRange(view.state, [nodeFrom, nodeTo]); + + // Get the mark nodes (the ~ characters) + const marks = node.getChildren('SubscriptMark'); + + if (!cursorInRange && marks.length >= 2) { + // Hide the opening and closing ~ marks + decorations.push(invisibleDecoration.range(marks[0].from, marks[0].to)); + decorations.push(invisibleDecoration.range(marks[marks.length - 1].from, marks[marks.length - 1].to)); + + // Apply subscript style to the content between marks + const contentStart = marks[0].to; + const contentEnd = marks[marks.length - 1].from; + if (contentStart < contentEnd) { + decorations.push( + Decoration.mark({ + class: 'cm-subscript' + }).range(contentStart, contentEnd) + ); + } + } + } + } + }); + } + + return Decoration.set(decorations, true); +} + +/** + * Plugin class with optimized update detection. + */ +class SubscriptSuperscriptPlugin { + decorations: DecorationSet; + private lastSelectionHead: number = -1; + + constructor(view: EditorView) { + this.decorations = buildDecorations(view); + this.lastSelectionHead = view.state.selection.main.head; + } + + update(update: ViewUpdate) { + if (update.docChanged || update.viewportChanged) { + this.decorations = buildDecorations(update.view); + this.lastSelectionHead = update.state.selection.main.head; + return; + } + + if (update.selectionSet) { + const newHead = update.state.selection.main.head; + if (newHead !== this.lastSelectionHead) { + this.decorations = buildDecorations(update.view); + this.lastSelectionHead = newHead; + } + } + } +} + +const subscriptSuperscriptPlugin = ViewPlugin.fromClass( + SubscriptSuperscriptPlugin, + { + decorations: (v) => v.decorations + } +); + +/** + * Base theme for subscript and superscript. + * Uses mark decoration instead of widget to avoid layout issues. + */ +const baseTheme = EditorView.baseTheme({ + '.cm-superscript': { + verticalAlign: 'super', + fontSize: '0.8em', + color: 'var(--cm-superscript-color, inherit)' + }, + '.cm-subscript': { + verticalAlign: 'sub', + fontSize: '0.8em', + color: 'var(--cm-subscript-color, inherit)' + } +}); diff --git a/frontend/src/views/editor/extensions/markdown/syntax/highlight.ts b/frontend/src/views/editor/extensions/markdown/syntax/highlight.ts new file mode 100644 index 0000000..f340d81 --- /dev/null +++ b/frontend/src/views/editor/extensions/markdown/syntax/highlight.ts @@ -0,0 +1,72 @@ +/** + * Highlight extension for Lezer Markdown parser. + * + * Parses ==highlight== syntax similar to Obsidian/Mark style. + * + * Syntax: ==text== → renders as highlighted text + * + * Example: + * - This is ==important== text → This is important text + */ + +import { MarkdownConfig } from '@lezer/markdown'; + +/** + * Highlight extension for Lezer Markdown. + * + * Defines: + * - Highlight: The container node for highlighted content + * - HighlightMark: The == delimiter marks + */ +export const Highlight: MarkdownConfig = { + defineNodes: [ + { name: 'Highlight' }, + { name: 'HighlightMark' } + ], + parseInline: [{ + name: 'Highlight', + parse(cx, next, pos) { + // Check for == delimiter (= is ASCII 61) + if (next !== 61 || cx.char(pos + 1) !== 61) { + return -1; + } + + // Don't match === or more (horizontal rule or other constructs) + if (cx.char(pos + 2) === 61) { + return -1; + } + + // Look for closing == delimiter + for (let i = pos + 2; i < cx.end - 1; i++) { + const char = cx.char(i); + + // Don't allow newlines within highlight + if (char === 10) { // newline + return -1; + } + + // Found potential closing == + if (char === 61 && cx.char(i + 1) === 61) { + // Make sure it's not === + if (i + 2 < cx.end && cx.char(i + 2) === 61) { + continue; + } + + // Create the element with marks + const element = cx.elt('Highlight', pos, i + 2, [ + cx.elt('HighlightMark', pos, pos + 2), + cx.elt('HighlightMark', i, i + 2) + ]); + return cx.addElement(element); + } + } + + return -1; + }, + // Parse after emphasis to avoid conflicts with other inline parsers + after: 'Emphasis' + }] +}; + +export default Highlight; + diff --git a/frontend/src/views/settings/pages/UpdatesPage.vue b/frontend/src/views/settings/pages/UpdatesPage.vue index a603ae5..62a30ed 100644 --- a/frontend/src/views/settings/pages/UpdatesPage.vue +++ b/frontend/src/views/settings/pages/UpdatesPage.vue @@ -6,19 +6,16 @@ import { useUpdateStore } from '@/stores/updateStore'; import SettingSection from '../components/SettingSection.vue'; import SettingItem from '../components/SettingItem.vue'; import ToggleSwitch from '../components/ToggleSwitch.vue'; -import markdownit from 'markdown-it' +import { marked } from 'marked'; const { t } = useI18n(); const configStore = useConfigStore(); const updateStore = useUpdateStore(); -// 初始化Remarkable实例并配置 -const md = markdownit({ - html: true, // 允许HTML - linkify: false, // 不解析链接 - typographer: true, // 开启智能引号 - xhtmlOut: true, // 使用xhtml语法输出 - breaks: true, // 允许换行 +// 配置marked +marked.setOptions({ + breaks: true, // 允许换行 + gfm: true, // GitHub风格Markdown }); // 计算属性 @@ -29,10 +26,10 @@ const autoCheckUpdates = computed({ } }); -// 使用Remarkable解析Markdown +// 使用marked解析Markdown const parseMarkdown = (markdown: string) => { if (!markdown) return ''; - return md.render(markdown); + return marked.parse(markdown) as string; }; // 处理更新按钮点击