diff --git a/bun.lock b/bun.lock index 25f7135..cfce1f4 100644 --- a/bun.lock +++ b/bun.lock @@ -54,11 +54,17 @@ }, "devDependencies": { "@tauri-apps/cli": "^2.7.1", - "@types/node": "^22.15.30", + "@types/node": "^24.2.1", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", "@types/sharp": "^0.32.0", + "@typescript-eslint/eslint-plugin": "^8.39.0", + "@typescript-eslint/parser": "^8.39.0", "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.33.0", + "monaco-editor": "^0.52.2", + "monaco-editor-webpack-plugin": "^7.1.0", + "monaco-themes": "^0.4.6", "sharp": "^0.34.2", "typescript": "~5.6.2", "vite": "^6.0.3", @@ -162,6 +168,24 @@ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="], + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.0", "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.21.0.tgz", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "https://registry.npmmirror.com/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="], + + "@eslint/core": ["@eslint/core@0.15.2", "https://registry.npmmirror.com/@eslint/core/-/core-0.15.2.tgz", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], + + "@eslint/js": ["@eslint/js@9.33.0", "https://registry.npmmirror.com/@eslint/js/-/js-9.33.0.tgz", {}, "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "https://registry.npmmirror.com/@eslint/object-schema/-/object-schema-2.1.6.tgz", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "https://registry.npmmirror.com/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="], + "@floating-ui/core": ["@floating-ui/core@1.7.1", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw=="], "@floating-ui/dom": ["@floating-ui/dom@1.7.1", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/utils": "^0.2.9" } }, "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ=="], @@ -172,6 +196,14 @@ "@hookform/resolvers": ["@hookform/resolvers@3.10.0", "", { "peerDependencies": { "react-hook-form": "^7.0.0" } }, "sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag=="], + "@humanfs/core": ["@humanfs/core@0.19.1", "https://registry.npmmirror.com/@humanfs/core/-/core-0.19.1.tgz", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.6", "https://registry.npmmirror.com/@humanfs/node/-/node-0.16.6.tgz", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "https://registry.npmmirror.com/@humanwhocodes/retry/-/retry-0.4.3.tgz", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="], "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="], @@ -222,6 +254,8 @@ "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.10", "https://registry.npmmirror.com/@jridgewell/source-map/-/source-map-0.3.10.tgz", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], @@ -230,6 +264,12 @@ "@monaco-editor/react": ["@monaco-editor/react@4.7.0", "https://registry.npmmirror.com/@monaco-editor/react/-/react-4.7.0.tgz", { "dependencies": { "@monaco-editor/loader": "^1.5.0" }, "peerDependencies": { "monaco-editor": ">= 0.25.0 < 1", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], @@ -478,17 +518,23 @@ "@types/diff": ["@types/diff@8.0.0", "", { "dependencies": { "diff": "*" } }, "sha512-o7jqJM04gfaYrdCecCVMbZhNdG6T1MHg/oQoRFdERLV+4d+V7FijhiEAbFu0Usww84Yijk9yH58U4Jk4HbtzZw=="], - "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], + "@types/eslint": ["@types/eslint@9.6.1", "https://registry.npmmirror.com/@types/eslint/-/eslint-9.6.1.tgz", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], + + "@types/eslint-scope": ["@types/eslint-scope@3.7.7", "https://registry.npmmirror.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", { "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="], + + "@types/estree": ["@types/estree@1.0.8", "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + "@types/json-schema": ["@types/json-schema@7.0.15", "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@22.15.32", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-3jigKqgSjsH6gYZv2nEsqdXfZqIFGAV36XYYjf9KGZ3PSG+IhLecqPnI310RvjutyMwifE2hhhNEklOUrvx/wA=="], + "@types/node": ["@types/node@24.2.1", "https://registry.npmmirror.com/@types/node/-/node-24.2.1.tgz", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], "@types/prismjs": ["@types/prismjs@1.26.5", "", {}, "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ=="], @@ -504,6 +550,26 @@ "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.0.tgz", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/type-utils": "8.39.0", "@typescript-eslint/utils": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.39.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.39.0.tgz", { "dependencies": { "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/types": "8.39.0", "@typescript-eslint/typescript-estree": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.39.0.tgz", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.39.0", "@typescript-eslint/types": "^8.39.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.39.0.tgz", { "dependencies": { "@typescript-eslint/types": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0" } }, "sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.0.tgz", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.39.0.tgz", { "dependencies": { "@typescript-eslint/types": "8.39.0", "@typescript-eslint/typescript-estree": "8.39.0", "@typescript-eslint/utils": "8.39.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.39.0.tgz", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.0.tgz", { "dependencies": { "@typescript-eslint/project-service": "8.39.0", "@typescript-eslint/tsconfig-utils": "8.39.0", "@typescript-eslint/types": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.39.0.tgz", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/types": "8.39.0", "@typescript-eslint/typescript-estree": "8.39.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.39.0", "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.0.tgz", { "dependencies": { "@typescript-eslint/types": "8.39.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA=="], + "@uiw/copy-to-clipboard": ["@uiw/copy-to-clipboard@1.0.17", "", {}, "sha512-O2GUHV90Iw2VrSLVLK0OmNIMdZ5fgEg4NhvtwINsX+eZ/Wf6DWD0TdsK9xwV7dNRnK/UI2mQtl0a2/kRgm1m1A=="], "@uiw/react-markdown-preview": ["@uiw/react-markdown-preview@5.1.4", "", { "dependencies": { "@babel/runtime": "^7.17.2", "@uiw/copy-to-clipboard": "~1.0.12", "react-markdown": "~9.0.1", "rehype-attr": "~3.0.1", "rehype-autolink-headings": "~7.1.0", "rehype-ignore": "^2.0.0", "rehype-prism-plus": "2.0.0", "rehype-raw": "^7.0.0", "rehype-rewrite": "~4.0.0", "rehype-slug": "~6.0.0", "remark-gfm": "~4.0.0", "remark-github-blockquote-alert": "^1.0.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-6k13WVNHCEaamz3vh54OQ1tseIXneKlir1+E/VFQBPq8PRod+gwLfYtiitDBWu+ZFttoiKPLZ7flgHrVM+JNOg=="], @@ -514,26 +580,88 @@ "@vitejs/plugin-react": ["@vitejs/plugin-react@4.5.2", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.11", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" } }, "sha512-QNVT3/Lxx99nMQWJWF7K4N6apUEuT0KlZA3mx/mVaoGj3smm/8rc8ezz15J1pcbcjDK0V15rpHetVfya08r76Q=="], + "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.14.1.tgz", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="], + + "@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.13.2", "https://registry.npmmirror.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", {}, "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA=="], + + "@webassemblyjs/helper-api-error": ["@webassemblyjs/helper-api-error@1.13.2", "https://registry.npmmirror.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", {}, "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ=="], + + "@webassemblyjs/helper-buffer": ["@webassemblyjs/helper-buffer@1.14.1", "https://registry.npmmirror.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", {}, "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA=="], + + "@webassemblyjs/helper-numbers": ["@webassemblyjs/helper-numbers@1.13.2", "https://registry.npmmirror.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", { "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA=="], + + "@webassemblyjs/helper-wasm-bytecode": ["@webassemblyjs/helper-wasm-bytecode@1.13.2", "https://registry.npmmirror.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", {}, "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA=="], + + "@webassemblyjs/helper-wasm-section": ["@webassemblyjs/helper-wasm-section@1.14.1", "https://registry.npmmirror.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/wasm-gen": "1.14.1" } }, "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw=="], + + "@webassemblyjs/ieee754": ["@webassemblyjs/ieee754@1.13.2", "https://registry.npmmirror.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", { "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw=="], + + "@webassemblyjs/leb128": ["@webassemblyjs/leb128@1.13.2", "https://registry.npmmirror.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", { "dependencies": { "@xtuc/long": "4.2.2" } }, "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw=="], + + "@webassemblyjs/utf8": ["@webassemblyjs/utf8@1.13.2", "https://registry.npmmirror.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", {}, "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ=="], + + "@webassemblyjs/wasm-edit": ["@webassemblyjs/wasm-edit@1.14.1", "https://registry.npmmirror.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/helper-wasm-section": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-opt": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1", "@webassemblyjs/wast-printer": "1.14.1" } }, "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ=="], + + "@webassemblyjs/wasm-gen": ["@webassemblyjs/wasm-gen@1.14.1", "https://registry.npmmirror.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg=="], + + "@webassemblyjs/wasm-opt": ["@webassemblyjs/wasm-opt@1.14.1", "https://registry.npmmirror.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1" } }, "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw=="], + + "@webassemblyjs/wasm-parser": ["@webassemblyjs/wasm-parser@1.14.1", "https://registry.npmmirror.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ=="], + + "@webassemblyjs/wast-printer": ["@webassemblyjs/wast-printer@1.14.1", "https://registry.npmmirror.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw=="], + + "@xtuc/ieee754": ["@xtuc/ieee754@1.2.0", "https://registry.npmmirror.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz", {}, "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="], + + "@xtuc/long": ["@xtuc/long@4.2.2", "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="], + + "acorn": ["acorn@8.15.0", "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "acorn-import-phases": ["acorn-import-phases@1.0.4", "https://registry.npmmirror.com/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", { "peerDependencies": { "acorn": "^8.14.0" } }, "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "ajv": ["ajv@6.12.6", "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ajv-formats": ["ajv-formats@2.1.1", "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-2.1.1.tgz", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="], + + "ajv-keywords": ["ajv-keywords@5.1.0", "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], + + "ansi-styles": ["ansi-styles@4.3.0", "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "ansi-to-html": ["ansi-to-html@0.7.2", "", { "dependencies": { "entities": "^2.2.0" }, "bin": { "ansi-to-html": "bin/ansi-to-html" } }, "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g=="], + "argparse": ["argparse@2.0.1", "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + "balanced-match": ["balanced-match@1.0.2", "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "base64-arraybuffer": ["base64-arraybuffer@1.0.2", "", {}, "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="], "bcp-47-match": ["bcp-47-match@2.0.3", "", {}, "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ=="], + "big.js": ["big.js@5.2.2", "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz", {}, "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="], + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + "brace-expansion": ["brace-expansion@1.1.12", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], "browserslist": ["browserslist@4.25.0", "", { "dependencies": { "caniuse-lite": "^1.0.30001718", "electron-to-chromium": "^1.5.160", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA=="], + "buffer-from": ["buffer-from@1.1.2", "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + + "callsites": ["callsites@3.1.0", "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + "caniuse-lite": ["caniuse-lite@1.0.30001723", "", {}, "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], + "chalk": ["chalk@4.1.2", "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "character-entities": ["character-entities@1.2.4", "", {}, "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw=="], "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], @@ -544,6 +672,8 @@ "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + "chrome-trace-event": ["chrome-trace-event@1.0.4", "https://registry.npmmirror.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", {}, "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ=="], + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], @@ -558,10 +688,16 @@ "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + "commander": ["commander@2.20.3", "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "concat-map": ["concat-map@0.0.1", "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], "core-js": ["core-js@3.44.0", "", {}, "sha512-aFCtd4l6GvAXwVEh3XbbVqJGHDJt0OZRa+5ePGx3LLwi12WfexqQxcsohb2wgsa/92xtl19Hd66G/L+TaAxDMw=="], + "cross-spawn": ["cross-spawn@7.0.6", "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "css-line-break": ["css-line-break@2.1.0", "", { "dependencies": { "utrie": "^1.0.2" } }, "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w=="], "css-selector-parser": ["css-selector-parser@3.1.2", "", {}, "sha512-WfUcL99xWDs7b3eZPoRszWVfbNo8ErCF15PTvVROjkShGlAfjIkG6hlfj/sl6/rfo5Q9x9ryJ3VqVnAZDA+gcw=="], @@ -598,6 +734,8 @@ "decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="], + "deep-is": ["deep-is@0.1.4", "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], @@ -614,32 +752,76 @@ "electron-to-chromium": ["electron-to-chromium@1.5.169", "", {}, "sha512-q7SQx6mkLy0GTJK9K9OiWeaBMV4XQtBSdf6MJUzDB/H/5tFXfIiX38Lci1Kl6SsgiEhz1SQI1ejEOU5asWEhwQ=="], + "emojis-list": ["emojis-list@3.0.0", "https://registry.npmmirror.com/emojis-list/-/emojis-list-3.0.0.tgz", {}, "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="], + "enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="], "entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], + "es-module-lexer": ["es-module-lexer@1.7.0", "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + "esbuild": ["esbuild@0.25.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.5", "@esbuild/android-arm": "0.25.5", "@esbuild/android-arm64": "0.25.5", "@esbuild/android-x64": "0.25.5", "@esbuild/darwin-arm64": "0.25.5", "@esbuild/darwin-x64": "0.25.5", "@esbuild/freebsd-arm64": "0.25.5", "@esbuild/freebsd-x64": "0.25.5", "@esbuild/linux-arm": "0.25.5", "@esbuild/linux-arm64": "0.25.5", "@esbuild/linux-ia32": "0.25.5", "@esbuild/linux-loong64": "0.25.5", "@esbuild/linux-mips64el": "0.25.5", "@esbuild/linux-ppc64": "0.25.5", "@esbuild/linux-riscv64": "0.25.5", "@esbuild/linux-s390x": "0.25.5", "@esbuild/linux-x64": "0.25.5", "@esbuild/netbsd-arm64": "0.25.5", "@esbuild/netbsd-x64": "0.25.5", "@esbuild/openbsd-arm64": "0.25.5", "@esbuild/openbsd-x64": "0.25.5", "@esbuild/sunos-x64": "0.25.5", "@esbuild/win32-arm64": "0.25.5", "@esbuild/win32-ia32": "0.25.5", "@esbuild/win32-x64": "0.25.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + "escape-string-regexp": ["escape-string-regexp@4.0.0", "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.33.0", "https://registry.npmmirror.com/eslint/-/eslint-9.33.0.tgz", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.33.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA=="], + + "eslint-scope": ["eslint-scope@8.4.0", "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-8.4.0.tgz", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "https://registry.npmmirror.com/espree/-/espree-10.4.0.tgz", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esquery": ["esquery@1.6.0", "https://registry.npmmirror.com/esquery/-/esquery-1.6.0.tgz", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], + + "esrecurse": ["esrecurse@4.3.0", "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], + "esutils": ["esutils@2.0.3", "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], + "events": ["events@3.3.0", "https://registry.npmmirror.com/events/-/events-3.3.0.tgz", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-equals": ["fast-equals@5.2.2", "", {}, "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw=="], + "fast-glob": ["fast-glob@3.3.3", "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", { "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" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fast-plist": ["fast-plist@0.1.3", "https://registry.npmmirror.com/fast-plist/-/fast-plist-0.1.3.tgz", {}, "sha512-d9cEfo/WcOezgPLAC/8t8wGb6YOD6JTCPMw2QcG2nAdFmyY+9rTUizCTaGjIZAloWENTEUMAPpkUAIJJJ0i96A=="], + + "fast-uri": ["fast-uri@3.0.6", "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.0.6.tgz", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="], + + "fastq": ["fastq@1.19.1", "https://registry.npmmirror.com/fastq/-/fastq-1.19.1.tgz", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], + "fault": ["fault@1.0.4", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA=="], "fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="], "fflate": ["fflate@0.4.8", "", {}, "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="], + "file-entry-cache": ["file-entry-cache@8.0.0", "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + "find-up": ["find-up@5.0.0", "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "https://registry.npmmirror.com/flat-cache/-/flat-cache-4.0.1.tgz", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.3.3", "https://registry.npmmirror.com/flatted/-/flatted-3.3.3.tgz", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + "format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="], "framer-motion": ["framer-motion@12.18.1", "", { "dependencies": { "motion-dom": "^12.18.1", "motion-utils": "^12.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-6o4EDuRPLk4LSZ1kRnnEOurbQ86MklVk+Y1rFBUKiF+d2pCdvMjWVu0ZkyMVCTwl5UyTH2n/zJEJx+jvTYuxow=="], @@ -652,10 +834,18 @@ "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], - "globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], + "glob-parent": ["glob-parent@6.0.2", "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "glob-to-regexp": ["glob-to-regexp@0.4.1", "https://registry.npmmirror.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], + + "globals": ["globals@14.0.0", "https://registry.npmmirror.com/globals/-/globals-14.0.0.tgz", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "graphemer": ["graphemer@1.4.0", "https://registry.npmmirror.com/graphemer/-/graphemer-1.4.0.tgz", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], + + "has-flag": ["has-flag@4.0.0", "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "hast-util-from-html": ["hast-util-from-html@2.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", "hast-util-from-parse5": "^8.0.0", "parse5": "^7.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw=="], "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="], @@ -700,6 +890,12 @@ "i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.0", "https://registry.npmmirror.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g=="], + "ignore": ["ignore@7.0.5", "https://registry.npmmirror.com/ignore/-/ignore-7.0.5.tgz", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "import-fresh": ["import-fresh@3.3.1", "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], @@ -722,14 +918,32 @@ "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + "isexe": ["isexe@2.0.0", "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "jest-worker": ["jest-worker@27.5.1", "https://registry.npmmirror.com/jest-worker/-/jest-worker-27.5.1.tgz", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="], + "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "js-yaml": ["js-yaml@4.1.0", "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "json-buffer": ["json-buffer@3.0.1", "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + "keyv": ["keyv@4.5.4", "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "levn": ["levn@0.4.1", "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + "lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="], "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="], @@ -752,8 +966,16 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="], + "loader-runner": ["loader-runner@4.3.0", "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz", {}, "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="], + + "loader-utils": ["loader-utils@2.0.4", "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" } }, "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw=="], + + "locate-path": ["locate-path@6.0.0", "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "lodash.merge": ["lodash.merge@4.6.2", "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], @@ -798,6 +1020,10 @@ "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + "merge-stream": ["merge-stream@2.0.0", "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "merge2": ["merge2@1.4.1", "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], @@ -856,6 +1082,12 @@ "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mime-db": ["mime-db@1.52.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "minimatch": ["minimatch@3.1.2", "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], "minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="], @@ -864,6 +1096,10 @@ "monaco-editor": ["monaco-editor@0.52.2", "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.52.2.tgz", {}, "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ=="], + "monaco-editor-webpack-plugin": ["monaco-editor-webpack-plugin@7.1.0", "https://registry.npmmirror.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-7.1.0.tgz", { "dependencies": { "loader-utils": "^2.0.2" }, "peerDependencies": { "monaco-editor": ">= 0.31.0", "webpack": "^4.5.0 || 5.x" } }, "sha512-ZjnGINHN963JQkFqjjcBtn1XBtUATDZBMgNQhDQwd78w2ukRhFXAPNgWuacaQiDZsUr4h1rWv5Mv6eriKuOSzA=="], + + "monaco-themes": ["monaco-themes@0.4.6", "https://registry.npmmirror.com/monaco-themes/-/monaco-themes-0.4.6.tgz", { "dependencies": { "fast-plist": "^0.1.3" } }, "sha512-g8E1CNT6bRyinPSQxVnNrs5b12zmKBpA83l3MEyOETr+KvoyUP4SS1AfHxyxaFBnLiyuyRwoPO4+R4PvzCJzPw=="], + "motion-dom": ["motion-dom@12.18.1", "", { "dependencies": { "motion-utils": "^12.18.1" } }, "sha512-dR/4EYT23Snd+eUSLrde63Ws3oXQtJNw/krgautvTfwrN/2cHfCZMdu6CeTxVfRRWREW3Fy1f5vobRDiBb/q+w=="], "motion-utils": ["motion-utils@12.18.1", "", {}, "sha512-az26YDU4WoDP0ueAkUtABLk2BIxe28d8NH1qWT8jPGhPyf44XTdDUh8pDk9OPphaSrR9McgpcJlgwSOIw/sfkA=="], @@ -874,6 +1110,10 @@ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "natural-compare": ["natural-compare@1.4.0", "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "neo-async": ["neo-async@2.6.2", "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], @@ -882,12 +1122,24 @@ "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + "optionator": ["optionator@0.9.4", "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "p-limit": ["p-limit@3.1.0", "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "parent-module": ["parent-module@1.0.1", "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + "parse-entities": ["parse-entities@2.0.0", "", { "dependencies": { "character-entities": "^1.0.0", "character-entities-legacy": "^1.0.0", "character-reference-invalid": "^1.0.0", "is-alphanumerical": "^1.0.0", "is-decimal": "^1.0.0", "is-hexadecimal": "^1.0.0" } }, "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ=="], "parse-numeric-range": ["parse-numeric-range@1.3.0", "", {}, "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ=="], "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + "path-exists": ["path-exists@4.0.0", "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-key": ["path-key@3.1.1", "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], @@ -898,12 +1150,20 @@ "preact": ["preact@10.27.0", "", {}, "sha512-/DTYoB6mwwgPytiqQTh/7SFRL98ZdiD8Sk8zIUVOxtwq4oWcwrcd1uno9fE/zZmUaUrFNYzbH14CPebOz9tZQw=="], + "prelude-ls": ["prelude-ls@1.2.1", "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + "punycode": ["punycode@2.3.1", "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "queue-microtask": ["queue-microtask@1.2.3", "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "randombytes": ["randombytes@2.1.0", "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], + "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], @@ -966,28 +1226,54 @@ "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], + "require-from-string": ["require-from-string@2.0.2", "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + + "resolve-from": ["resolve-from@4.0.0", "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "reusify": ["reusify@1.1.0", "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + "rollup": ["rollup@4.43.0", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.43.0", "@rollup/rollup-android-arm64": "4.43.0", "@rollup/rollup-darwin-arm64": "4.43.0", "@rollup/rollup-darwin-x64": "4.43.0", "@rollup/rollup-freebsd-arm64": "4.43.0", "@rollup/rollup-freebsd-x64": "4.43.0", "@rollup/rollup-linux-arm-gnueabihf": "4.43.0", "@rollup/rollup-linux-arm-musleabihf": "4.43.0", "@rollup/rollup-linux-arm64-gnu": "4.43.0", "@rollup/rollup-linux-arm64-musl": "4.43.0", "@rollup/rollup-linux-loongarch64-gnu": "4.43.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.43.0", "@rollup/rollup-linux-riscv64-gnu": "4.43.0", "@rollup/rollup-linux-riscv64-musl": "4.43.0", "@rollup/rollup-linux-s390x-gnu": "4.43.0", "@rollup/rollup-linux-x64-gnu": "4.43.0", "@rollup/rollup-linux-x64-musl": "4.43.0", "@rollup/rollup-win32-arm64-msvc": "4.43.0", "@rollup/rollup-win32-ia32-msvc": "4.43.0", "@rollup/rollup-win32-x64-msvc": "4.43.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg=="], + "run-parallel": ["run-parallel@1.2.0", "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "safe-buffer": ["safe-buffer@5.2.1", "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], + "schema-utils": ["schema-utils@4.3.2", "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.3.2.tgz", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" } }, "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ=="], + "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "serialize-javascript": ["serialize-javascript@6.0.2", "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], + "sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="], + "shebang-command": ["shebang-command@2.0.0", "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="], + "source-map": ["source-map@0.6.1", "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "source-map-support": ["source-map-support@0.5.21", "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], "state-local": ["state-local@1.0.7", "https://registry.npmmirror.com/state-local/-/state-local-1.0.7.tgz", {}, "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w=="], "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + "strip-json-comments": ["strip-json-comments@3.1.1", "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + "style-to-js": ["style-to-js@1.1.17", "", { "dependencies": { "style-to-object": "1.0.9" } }, "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA=="], "style-to-object": ["style-to-object@1.0.9", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw=="], + "supports-color": ["supports-color@7.2.0", "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="], "tailwindcss": ["tailwindcss@4.1.10", "", {}, "sha512-P3nr6WkvKV/ONsTzj6Gb57sWPMX29EPNPopo7+FcpkQaNsrNpZ1pv8QmrYI2RqEKD7mlGqLnGovlcYnBK0IqUA=="], @@ -996,6 +1282,10 @@ "tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="], + "terser": ["terser@5.43.1", "https://registry.npmmirror.com/terser/-/terser-5.43.1.tgz", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg=="], + + "terser-webpack-plugin": ["terser-webpack-plugin@5.3.14", "https://registry.npmmirror.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw=="], + "text-segmentation": ["text-segmentation@1.0.3", "", { "dependencies": { "utrie": "^1.0.2" } }, "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw=="], "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], @@ -1008,11 +1298,15 @@ "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + "ts-api-utils": ["ts-api-utils@2.1.0", "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "type-check": ["type-check@0.4.0", "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + "typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], - "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "undici-types": ["undici-types@7.10.0", "https://registry.npmmirror.com/undici-types/-/undici-types-7.10.0.tgz", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], @@ -1030,6 +1324,8 @@ "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], + "uri-js": ["uri-js@4.4.1", "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], @@ -1048,14 +1344,26 @@ "void-elements": ["void-elements@3.1.0", "https://registry.npmmirror.com/void-elements/-/void-elements-3.1.0.tgz", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="], + "watchpack": ["watchpack@2.4.4", "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.4.tgz", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA=="], + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], "web-vitals": ["web-vitals@4.2.4", "", {}, "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw=="], + "webpack": ["webpack@5.101.0", "https://registry.npmmirror.com/webpack/-/webpack-5.101.0.tgz", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.2", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-B4t+nJqytPeuZlHuIKTbalhljIFXeNRqrUGAQgTGlfOl2lXXKXw+yZu6bicycP+PUlM44CxBjCFD6aciKFT3LQ=="], + + "webpack-sources": ["webpack-sources@3.3.3", "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.3.3.tgz", {}, "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg=="], + + "which": ["which@2.0.2", "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "word-wrap": ["word-wrap@1.2.5", "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "yocto-queue": ["yocto-queue@0.1.0", "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "zod": ["zod@3.25.67", "", {}, "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw=="], "zustand": ["zustand@5.0.6", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A=="], @@ -1066,6 +1374,14 @@ "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/ignore": ["ignore@5.3.2", "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "https://registry.npmmirror.com/@humanwhocodes/retry/-/retry-0.3.1.tgz", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], + "@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="], @@ -1080,14 +1396,28 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@types/estree-jsx/@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@uiw/react-markdown-preview/react-markdown": ["react-markdown@9.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-Yk7Z94dbgYTOrdk41Z74GoKA7rThnsbbqBTRYuxoe08qvfQ9tJVhmAKw6BJS/ZORG7kTy/s1QvYzSuaoBA1qfw=="], "@uiw/react-markdown-preview/rehype-prism-plus": ["rehype-prism-plus@2.0.0", "", { "dependencies": { "hast-util-to-string": "^3.0.0", "parse-numeric-range": "^1.3.0", "refractor": "^4.8.0", "rehype-parse": "^9.0.0", "unist-util-filter": "^5.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ=="], + "ajv-formats/ajv": ["ajv@8.17.1", "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], + + "ajv-keywords/ajv": ["ajv@8.17.1", "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], + "decode-named-character-reference/character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + "eslint/ignore": ["ignore@5.3.2", "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "hast-util-from-parse5/hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], + "hast-util-to-jsx-runtime/@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], + "hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="], "hastscript/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="], @@ -1098,8 +1428,12 @@ "hastscript/space-separated-tokens": ["space-separated-tokens@1.1.5", "", {}, "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA=="], + "jest-worker/supports-color": ["supports-color@8.1.1", "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + "mdast-util-mdx-jsx/parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], @@ -1112,10 +1446,22 @@ "rehype-prism-plus/refractor": ["refractor@4.9.0", "", { "dependencies": { "@types/hast": "^2.0.0", "@types/prismjs": "^1.0.0", "hastscript": "^7.0.0", "parse-entities": "^4.0.0" } }, "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og=="], + "rollup/@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], + + "schema-utils/ajv": ["ajv@8.17.1", "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], + "stringify-entities/character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], + "webpack/eslint-scope": ["eslint-scope@5.1.1", "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "@uiw/react-markdown-preview/rehype-prism-plus/refractor": ["refractor@4.9.0", "", { "dependencies": { "@types/hast": "^2.0.0", "@types/prismjs": "^1.0.0", "hastscript": "^7.0.0", "parse-entities": "^4.0.0" } }, "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og=="], + "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "hast-util-from-parse5/hastscript/hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="], "hastscript/@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], @@ -1138,6 +1484,10 @@ "rehype-prism-plus/refractor/parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], + "schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], + "@uiw/react-markdown-preview/rehype-prism-plus/refractor/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="], "@uiw/react-markdown-preview/rehype-prism-plus/refractor/hastscript": ["hastscript@7.2.0", "", { "dependencies": { "@types/hast": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^3.0.0", "property-information": "^6.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw=="], diff --git a/package.json b/package.json index 847d7b9..737af76 100644 --- a/package.json +++ b/package.json @@ -62,11 +62,17 @@ }, "devDependencies": { "@tauri-apps/cli": "^2.7.1", - "@types/node": "^22.15.30", + "@types/node": "^24.2.1", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", "@types/sharp": "^0.32.0", + "@typescript-eslint/eslint-plugin": "^8.39.0", + "@typescript-eslint/parser": "^8.39.0", "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.33.0", + "monaco-editor": "^0.52.2", + "monaco-editor-webpack-plugin": "^7.1.0", + "monaco-themes": "^0.4.6", "sharp": "^0.34.2", "typescript": "~5.6.2", "vite": "^6.0.3" diff --git a/src-tauri/src/commands/filesystem.rs b/src-tauri/src/commands/filesystem.rs new file mode 100644 index 0000000..546ed4a --- /dev/null +++ b/src-tauri/src/commands/filesystem.rs @@ -0,0 +1,264 @@ +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::Path; +use tauri::Emitter; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct FileNode { + pub name: String, + pub path: String, + pub file_type: String, // "file" or "directory" + pub children: Option>, + pub size: Option, + pub modified: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct FileSystemChange { + pub path: String, + pub change_type: String, // "created", "modified", "deleted" +} + +/// 读取文件内容 +#[tauri::command] +pub async fn read_file(path: String) -> Result { + fs::read_to_string(&path) + .map_err(|e| format!("Failed to read file: {}", e)) +} + +/// 写入文件内容 +#[tauri::command] +pub async fn write_file(path: String, content: String) -> Result<(), String> { + fs::write(&path, content) + .map_err(|e| format!("Failed to write file: {}", e)) +} + +/// 读取目录树结构 +#[tauri::command] +pub async fn read_directory_tree( + path: String, + max_depth: Option, + ignore_patterns: Option>, +) -> Result { + let path = Path::new(&path); + if !path.exists() { + return Err(format!("Path does not exist: {}", path.display())); + } + + let max_depth = max_depth.unwrap_or(5); + let ignore_patterns = ignore_patterns.unwrap_or_else(|| vec![ + String::from("node_modules"), + String::from(".git"), + String::from("target"), + String::from("dist"), + String::from("build"), + String::from(".idea"), + String::from(".vscode"), + String::from("__pycache__"), + String::from(".DS_Store"), + ]); + + read_directory_recursive(path, 0, max_depth, &ignore_patterns) + .map_err(|e| e.to_string()) +} + +fn read_directory_recursive( + path: &Path, + current_depth: u32, + max_depth: u32, + ignore_patterns: &[String], +) -> std::io::Result { + let name = path.file_name() + .and_then(|n| n.to_str()) + .unwrap_or("") + .to_string(); + + let metadata = fs::metadata(path)?; + + let node = if metadata.is_dir() { + let mut children = Vec::new(); + + if current_depth < max_depth { + // Check if directory should be ignored + let should_ignore = ignore_patterns.iter().any(|pattern| { + &name == pattern || name.starts_with('.') + }); + + if !should_ignore { + let entries = fs::read_dir(path)?; + for entry in entries { + let entry = entry?; + let child_path = entry.path(); + + // Skip symlinks to avoid infinite loops + if let Ok(meta) = entry.metadata() { + if !meta.file_type().is_symlink() { + if let Ok(child_node) = read_directory_recursive( + &child_path, + current_depth + 1, + max_depth, + ignore_patterns, + ) { + children.push(child_node); + } + } + } + } + + // Sort children: directories first, then files, alphabetically + children.sort_by(|a, b| { + match (a.file_type.as_str(), b.file_type.as_str()) { + ("directory", "file") => std::cmp::Ordering::Less, + ("file", "directory") => std::cmp::Ordering::Greater, + _ => a.name.to_lowercase().cmp(&b.name.to_lowercase()), + } + }); + } + } + + FileNode { + name, + path: path.to_string_lossy().to_string(), + file_type: String::from("directory"), + children: Some(children), + size: None, + modified: metadata.modified() + .ok() + .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|d| d.as_secs()), + } + } else { + FileNode { + name, + path: path.to_string_lossy().to_string(), + file_type: String::from("file"), + children: None, + size: Some(metadata.len()), + modified: metadata.modified() + .ok() + .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|d| d.as_secs()), + } + }; + + Ok(node) +} + +/// 搜索文件 +#[tauri::command] +pub async fn search_files_by_name( + base_path: String, + query: String, + max_results: Option, +) -> Result, String> { + let base_path = Path::new(&base_path); + if !base_path.exists() { + return Err(format!("Path does not exist: {}", base_path.display())); + } + + let query_lower = query.to_lowercase(); + let max_results = max_results.unwrap_or(100); + let mut results = Vec::new(); + + search_recursive(base_path, &query_lower, &mut results, max_results)?; + + Ok(results) +} + +fn search_recursive( + dir: &Path, + query: &str, + results: &mut Vec, + max_results: usize, +) -> Result<(), String> { + if results.len() >= max_results { + return Ok(()); + } + + let entries = fs::read_dir(dir) + .map_err(|e| format!("Failed to read directory: {}", e))?; + + for entry in entries { + if results.len() >= max_results { + break; + } + + let entry = entry.map_err(|e| format!("Failed to read entry: {}", e))?; + let path = entry.path(); + let file_name = path.file_name() + .and_then(|n| n.to_str()) + .unwrap_or("") + .to_lowercase(); + + if file_name.contains(query) { + results.push(path.to_string_lossy().to_string()); + } + + if path.is_dir() { + // Skip hidden directories and common ignore patterns + if !file_name.starts_with('.') + && file_name != "node_modules" + && file_name != "target" + && file_name != "dist" { + let _ = search_recursive(&path, query, results, max_results); + } + } + } + + Ok(()) +} + +/// 获取文件信息 +#[tauri::command] +pub async fn get_file_info(path: String) -> Result { + let path = Path::new(&path); + if !path.exists() { + return Err(format!("Path does not exist: {}", path.display())); + } + + let metadata = fs::metadata(path) + .map_err(|e| format!("Failed to get metadata: {}", e))?; + + let name = path.file_name() + .and_then(|n| n.to_str()) + .unwrap_or("") + .to_string(); + + Ok(FileNode { + name, + path: path.to_string_lossy().to_string(), + file_type: if metadata.is_dir() { + String::from("directory") + } else { + String::from("file") + }, + children: None, + size: if metadata.is_file() { + Some(metadata.len()) + } else { + None + }, + modified: metadata.modified() + .ok() + .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|d| d.as_secs()), + }) +} + +/// 监听文件系统变化(简化版本) +#[tauri::command] +pub async fn watch_directory( + app: tauri::AppHandle, + path: String, +) -> Result<(), String> { + // 这里可以集成 notify crate 来实现文件系统监听 + // 为了简化,先返回成功 + + // 发送测试事件 + app.emit("file-system-change", FileSystemChange { + path: path.clone(), + change_type: String::from("watching"), + }).map_err(|e| e.to_string())?; + + Ok(()) +} \ No newline at end of file diff --git a/src-tauri/src/commands/git.rs b/src-tauri/src/commands/git.rs new file mode 100644 index 0000000..fc9994c --- /dev/null +++ b/src-tauri/src/commands/git.rs @@ -0,0 +1,426 @@ +use serde::{Deserialize, Serialize}; +use std::process::Command; +use std::path::Path; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct GitStatus { + pub branch: String, + pub ahead: u32, + pub behind: u32, + pub staged: Vec, + pub modified: Vec, + pub untracked: Vec, + pub conflicted: Vec, + pub is_clean: bool, + pub remote_url: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct GitFileStatus { + pub path: String, + pub status: String, // "modified", "added", "deleted", "renamed" + pub staged: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct GitCommit { + pub hash: String, + pub short_hash: String, + pub author: String, + pub email: String, + pub date: String, + pub message: String, + pub files_changed: u32, + pub insertions: u32, + pub deletions: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GitBranch { + pub name: String, + pub is_current: bool, + pub remote: Option, + pub last_commit: Option, +} + +/// 获取 Git 状态 +#[tauri::command] +pub async fn get_git_status(path: String) -> Result { + let path = Path::new(&path); + if !path.exists() { + return Err(format!("Path does not exist: {}", path.display())); + } + + // Check if it's a git repository + let git_check = Command::new("git") + .arg("rev-parse") + .arg("--git-dir") + .current_dir(path) + .output() + .map_err(|e| format!("Failed to execute git command: {}", e))?; + + if !git_check.status.success() { + return Err("Not a git repository".to_string()); + } + + // Get current branch + let branch_output = Command::new("git") + .args(&["rev-parse", "--abbrev-ref", "HEAD"]) + .current_dir(path) + .output() + .map_err(|e| format!("Failed to get branch: {}", e))?; + + let branch = String::from_utf8_lossy(&branch_output.stdout) + .trim() + .to_string(); + + // Get remote tracking info + let (ahead, behind) = get_tracking_info(path)?; + + // Get status + let status_output = Command::new("git") + .args(&["status", "--porcelain=v1"]) + .current_dir(path) + .output() + .map_err(|e| format!("Failed to get status: {}", e))?; + + let status_text = String::from_utf8_lossy(&status_output.stdout); + let (staged, modified, untracked, conflicted) = parse_git_status(&status_text); + + // Get remote URL + let remote_output = Command::new("git") + .args(&["remote", "get-url", "origin"]) + .current_dir(path) + .output() + .ok(); + + let remote_url = remote_output + .and_then(|o| { + if o.status.success() { + Some(String::from_utf8_lossy(&o.stdout).trim().to_string()) + } else { + None + } + }); + + let is_clean = staged.is_empty() && modified.is_empty() && untracked.is_empty(); + + Ok(GitStatus { + branch, + ahead, + behind, + staged, + modified, + untracked, + conflicted, + is_clean, + remote_url, + }) +} + +fn get_tracking_info(path: &Path) -> Result<(u32, u32), String> { + // Get ahead/behind counts + let ahead_output = Command::new("git") + .args(&["rev-list", "--count", "@{u}..HEAD"]) + .current_dir(path) + .output(); + + let behind_output = Command::new("git") + .args(&["rev-list", "--count", "HEAD..@{u}"]) + .current_dir(path) + .output(); + + let ahead = ahead_output + .ok() + .and_then(|o| { + if o.status.success() { + String::from_utf8_lossy(&o.stdout) + .trim() + .parse::() + .ok() + } else { + None + } + }) + .unwrap_or(0); + + let behind = behind_output + .ok() + .and_then(|o| { + if o.status.success() { + String::from_utf8_lossy(&o.stdout) + .trim() + .parse::() + .ok() + } else { + None + } + }) + .unwrap_or(0); + + Ok((ahead, behind)) +} + +fn parse_git_status(status_text: &str) -> (Vec, Vec, Vec, Vec) { + let mut staged = Vec::new(); + let mut modified = Vec::new(); + let mut untracked = Vec::new(); + let mut conflicted = Vec::new(); + + for line in status_text.lines() { + if line.len() < 3 { + continue; + } + + let status_code = &line[0..2]; + let file_path = line[3..].trim().to_string(); + + match status_code { + "M " => modified.push(GitFileStatus { + path: file_path, + status: "modified".to_string(), + staged: false, + }), + " M" => modified.push(GitFileStatus { + path: file_path, + status: "modified".to_string(), + staged: false, + }), + "MM" => { + staged.push(GitFileStatus { + path: file_path.clone(), + status: "modified".to_string(), + staged: true, + }); + modified.push(GitFileStatus { + path: file_path, + status: "modified".to_string(), + staged: false, + }); + }, + "A " | "AM" => staged.push(GitFileStatus { + path: file_path, + status: "added".to_string(), + staged: true, + }), + "D " => staged.push(GitFileStatus { + path: file_path, + status: "deleted".to_string(), + staged: true, + }), + " D" => modified.push(GitFileStatus { + path: file_path, + status: "deleted".to_string(), + staged: false, + }), + "R " => staged.push(GitFileStatus { + path: file_path, + status: "renamed".to_string(), + staged: true, + }), + "??" => untracked.push(GitFileStatus { + path: file_path, + status: "untracked".to_string(), + staged: false, + }), + "UU" | "AA" | "DD" => conflicted.push(GitFileStatus { + path: file_path, + status: "conflicted".to_string(), + staged: false, + }), + _ => {} + } + } + + (staged, modified, untracked, conflicted) +} + +/// 获取 Git 提交历史 +#[tauri::command] +pub async fn get_git_history( + path: String, + limit: Option, + branch: Option, +) -> Result, String> { + let path = Path::new(&path); + if !path.exists() { + return Err(format!("Path does not exist: {}", path.display())); + } + + let limit = limit.unwrap_or(50); + let branch = branch.unwrap_or_else(|| "HEAD".to_string()); + + // Get commit logs with stats + let log_output = Command::new("git") + .args(&[ + "log", + &branch, + &format!("-{}", limit), + "--pretty=format:%H|%h|%an|%ae|%ad|%s", + "--date=iso", + "--numstat", + ]) + .current_dir(path) + .output() + .map_err(|e| format!("Failed to get git history: {}", e))?; + + if !log_output.status.success() { + return Err("Failed to get git history".to_string()); + } + + let log_text = String::from_utf8_lossy(&log_output.stdout); + parse_git_log(&log_text) +} + +fn parse_git_log(log_text: &str) -> Result, String> { + let mut commits = Vec::new(); + let mut current_commit: Option = None; + let mut files_changed = 0u32; + let mut insertions = 0u32; + let mut deletions = 0u32; + + for line in log_text.lines() { + if line.contains('|') && line.matches('|').count() == 5 { + // Save previous commit if exists + if let Some(mut commit) = current_commit.take() { + commit.files_changed = files_changed; + commit.insertions = insertions; + commit.deletions = deletions; + commits.push(commit); + } + + // Reset counters + files_changed = 0; + insertions = 0; + deletions = 0; + + // Parse new commit + let parts: Vec<&str> = line.split('|').collect(); + if parts.len() >= 6 { + current_commit = Some(GitCommit { + hash: parts[0].to_string(), + short_hash: parts[1].to_string(), + author: parts[2].to_string(), + email: parts[3].to_string(), + date: parts[4].to_string(), + message: parts[5].to_string(), + files_changed: 0, + insertions: 0, + deletions: 0, + }); + } + } else if !line.trim().is_empty() && current_commit.is_some() { + // Parse numstat line + let parts: Vec<&str> = line.split_whitespace().collect(); + if parts.len() >= 2 { + if let Ok(added) = parts[0].parse::() { + insertions += added; + } + if let Ok(removed) = parts[1].parse::() { + deletions += removed; + } + files_changed += 1; + } + } + } + + // Save last commit + if let Some(mut commit) = current_commit { + commit.files_changed = files_changed; + commit.insertions = insertions; + commit.deletions = deletions; + commits.push(commit); + } + + Ok(commits) +} + +/// 获取 Git 分支列表 +#[tauri::command] +pub async fn get_git_branches(path: String) -> Result, String> { + let path = Path::new(&path); + if !path.exists() { + return Err(format!("Path does not exist: {}", path.display())); + } + + // Get all branches + let branch_output = Command::new("git") + .args(&["branch", "-a", "-v"]) + .current_dir(path) + .output() + .map_err(|e| format!("Failed to get branches: {}", e))?; + + if !branch_output.status.success() { + return Err("Failed to get branches".to_string()); + } + + let branch_text = String::from_utf8_lossy(&branch_output.stdout); + let mut branches = Vec::new(); + + for line in branch_text.lines() { + let is_current = line.starts_with('*'); + let line = line.trim_start_matches('*').trim(); + + let parts: Vec<&str> = line.split_whitespace().collect(); + if parts.is_empty() { + continue; + } + + let name = parts[0].to_string(); + let last_commit = if parts.len() > 1 { + Some(parts[1].to_string()) + } else { + None + }; + + let remote = if name.starts_with("remotes/") { + Some(name.trim_start_matches("remotes/").to_string()) + } else { + None + }; + + branches.push(GitBranch { + name: name.trim_start_matches("remotes/").to_string(), + is_current, + remote, + last_commit, + }); + } + + Ok(branches) +} + +/// 获取文件的 Git diff +#[tauri::command] +pub async fn get_git_diff( + path: String, + file_path: Option, + staged: Option, +) -> Result { + let path = Path::new(&path); + if !path.exists() { + return Err(format!("Path does not exist: {}", path.display())); + } + + let mut cmd = Command::new("git"); + cmd.arg("diff"); + + if staged.unwrap_or(false) { + cmd.arg("--cached"); + } + + if let Some(file) = file_path { + cmd.arg(file); + } + + let diff_output = cmd + .current_dir(path) + .output() + .map_err(|e| format!("Failed to get diff: {}", e))?; + + if !diff_output.status.success() { + return Err("Failed to get diff".to_string()); + } + + Ok(String::from_utf8_lossy(&diff_output.stdout).to_string()) +} \ No newline at end of file diff --git a/src/components/ClaudeCodeSession.tsx b/src/components/ClaudeCodeSession.tsx index 8ff2b27..783dc59 100644 --- a/src/components/ClaudeCodeSession.tsx +++ b/src/components/ClaudeCodeSession.tsx @@ -35,7 +35,7 @@ import { SplitPane } from "@/components/ui/split-pane"; import { WebviewPreview } from "./WebviewPreview"; import { FileExplorerPanel } from "./FileExplorerPanel"; import { GitPanel } from "./GitPanel"; -import { FileEditor } from "./FileEditor"; +import { FileEditorEnhanced } from "./FileEditorEnhanced"; import type { ClaudeStreamMessage } from "./AgentExecution"; import { useVirtualizer } from "@tanstack/react-virtual"; import { useTrackEvent, useComponentMetrics, useWorkflowTracking } from "@/hooks"; @@ -1504,9 +1504,9 @@ export const ClaudeCodeSession: React.FC = ({ className="h-full" /> ) : editingFile ? ( - // File Editor layout + // File Editor layout with enhanced features
- setEditingFile(null)} className="flex-1" diff --git a/src/components/FileEditor.tsx b/src/components/FileEditor.tsx new file mode 100644 index 0000000..9eccce3 --- /dev/null +++ b/src/components/FileEditor.tsx @@ -0,0 +1,301 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { invoke } from "@tauri-apps/api/core"; +import { + X, + Save, + FileText, + AlertCircle, + Check, + Loader2 +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { useTranslation } from "react-i18next"; +import Editor from "@monaco-editor/react"; +import { motion, AnimatePresence } from "framer-motion"; + +interface FileEditorProps { + filePath: string; + onClose: () => void; + className?: string; +} + +// 根据文件扩展名获取语言 +const getLanguageFromPath = (path: string): string => { + const ext = path.split(".").pop()?.toLowerCase(); + + const languageMap: Record = { + // JavaScript/TypeScript + js: "javascript", + jsx: "javascript", + ts: "typescript", + tsx: "typescript", + + // Web + html: "html", + htm: "html", + css: "css", + scss: "scss", + sass: "sass", + less: "less", + + // Programming Languages + py: "python", + java: "java", + c: "c", + cpp: "cpp", + cc: "cpp", + cxx: "cpp", + cs: "csharp", + php: "php", + rb: "ruby", + go: "go", + rs: "rust", + kt: "kotlin", + swift: "swift", + m: "objective-c", + scala: "scala", + sh: "shell", + bash: "shell", + zsh: "shell", + fish: "shell", + ps1: "powershell", + r: "r", + lua: "lua", + perl: "perl", + + // Data/Config + json: "json", + xml: "xml", + yaml: "yaml", + yml: "yaml", + toml: "toml", + ini: "ini", + cfg: "ini", + conf: "ini", + + // Documentation + md: "markdown", + markdown: "markdown", + rst: "restructuredtext", + tex: "latex", + + // Database + sql: "sql", + + // Others + dockerfile: "dockerfile", + makefile: "makefile", + cmake: "cmake", + gradle: "gradle", + }; + + return languageMap[ext || ""] || "plaintext"; +}; + +export const FileEditor: React.FC = ({ + filePath, + onClose, + className, +}) => { + const { t } = useTranslation(); + const [content, setContent] = useState(""); + const [originalContent, setOriginalContent] = useState(""); + const [loading, setLoading] = useState(false); + const [saving, setSaving] = useState(false); + const [error, setError] = useState(null); + const [saved, setSaved] = useState(false); + const [hasChanges, setHasChanges] = useState(false); + + const fileName = filePath.split("/").pop() || filePath; + const language = getLanguageFromPath(filePath); + + // 加载文件内容 + const loadFile = useCallback(async () => { + if (!filePath) return; + + try { + setLoading(true); + setError(null); + + const fileContent = await invoke("read_file", { + path: filePath, + }); + + setContent(fileContent); + setOriginalContent(fileContent); + setHasChanges(false); + } catch (err) { + console.error("Failed to load file:", err); + setError(err instanceof Error ? err.message : "Failed to load file"); + } finally { + setLoading(false); + } + }, [filePath]); + + // 保存文件 + const saveFile = useCallback(async () => { + if (!filePath || !hasChanges) return; + + try { + setSaving(true); + setError(null); + + await invoke("write_file", { + path: filePath, + content: content, + }); + + setOriginalContent(content); + setHasChanges(false); + setSaved(true); + + // 显示保存成功提示 + setTimeout(() => setSaved(false), 2000); + } catch (err) { + console.error("Failed to save file:", err); + setError(err instanceof Error ? err.message : "Failed to save file"); + } finally { + setSaving(false); + } + }, [filePath, content, hasChanges]); + + // 处理内容变化 + const handleContentChange = (value: string | undefined) => { + if (value !== undefined) { + setContent(value); + setHasChanges(value !== originalContent); + } + }; + + // 处理关闭 + const handleClose = () => { + if (hasChanges) { + if (confirm(t("app.unsavedChangesConfirm"))) { + onClose(); + } + } else { + onClose(); + } + }; + + // 快捷键处理 + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + // Ctrl/Cmd + S 保存 + if ((e.ctrlKey || e.metaKey) && e.key === "s" && hasChanges) { + e.preventDefault(); + saveFile(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [hasChanges, saveFile]); + + // 加载文件 + useEffect(() => { + if (filePath) { + loadFile(); + } + }, [filePath, loadFile]); + + return ( +
+ {/* Header */} +
+
+ +
+ {fileName} + {hasChanges && ( + + {t("app.modified")} + + )} + + {saved && ( + + + {t("app.saved")} + + )} + +
+
+ +
+ {hasChanges && ( + + )} + + +
+
+ + {/* Editor */} + {error ? ( +
+ +

{t("app.error")}

+

{error}

+
+ ) : loading ? ( +
+ +
+ ) : ( +
+ +
+ )} +
+ ); +}; + +export default FileEditor; \ No newline at end of file diff --git a/src/components/FileEditorEnhanced.tsx b/src/components/FileEditorEnhanced.tsx new file mode 100644 index 0000000..4536255 --- /dev/null +++ b/src/components/FileEditorEnhanced.tsx @@ -0,0 +1,674 @@ +import React, { useState, useEffect, useCallback, useRef } from "react"; +import { invoke } from "@tauri-apps/api/core"; +import { + X, + Save, + AlertCircle, + Check, + Loader2, + Maximize2, + Minimize2, + Settings2, + FileCode2, + Sparkles, + Bug, + Zap, + AlertTriangle, + Info +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { useTranslation } from "react-i18next"; +import Editor, { Monaco } from "@monaco-editor/react"; +import { motion, AnimatePresence } from "framer-motion"; +import * as monaco from "monaco-editor"; +import { + initializeMonaco, + formatDocument +} from "@/lib/monaco-config"; +import { setupRealtimeLinting } from "@/lib/eslint-integration"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +interface FileEditorEnhancedProps { + filePath: string; + onClose: () => void; + className?: string; +} + +// 根据文件扩展名获取语言 +const getLanguageFromPath = (path: string): string => { + const ext = path.split(".").pop()?.toLowerCase(); + + const languageMap: Record = { + // JavaScript/TypeScript + js: "javascript", + jsx: "javascript", + mjs: "javascript", + ts: "typescript", + tsx: "typescript", + + // Web + html: "html", + htm: "html", + css: "css", + scss: "scss", + sass: "sass", + less: "less", + + // Programming Languages + py: "python", + java: "java", + c: "c", + cpp: "cpp", + cc: "cpp", + cxx: "cpp", + cs: "csharp", + php: "php", + rb: "ruby", + go: "go", + rs: "rust", + kt: "kotlin", + swift: "swift", + m: "objective-c", + scala: "scala", + sh: "shell", + bash: "shell", + zsh: "shell", + fish: "shell", + ps1: "powershell", + r: "r", + lua: "lua", + perl: "perl", + + // Data/Config + json: "json", + jsonc: "json", + xml: "xml", + yaml: "yaml", + yml: "yaml", + toml: "toml", + ini: "ini", + cfg: "ini", + conf: "ini", + + // Documentation + md: "markdown", + markdown: "markdown", + rst: "restructuredtext", + tex: "latex", + + // Database + sql: "sql", + mysql: "mysql", + pgsql: "pgsql", + + // Others + dockerfile: "dockerfile", + makefile: "makefile", + cmake: "cmake", + gradle: "gradle", + graphql: "graphql", + proto: "protobuf", + }; + + return languageMap[ext || ""] || "plaintext"; +}; + +// 诊断信息接口 +interface DiagnosticInfo { + line: number; + column: number; + message: string; + severity: 'error' | 'warning' | 'info'; + source?: string; +} + +export const FileEditorEnhanced: React.FC = ({ + filePath, + onClose, + className, +}) => { + const { t } = useTranslation(); + const [content, setContent] = useState(""); + const [originalContent, setOriginalContent] = useState(""); + const [loading, setLoading] = useState(false); + const [saving, setSaving] = useState(false); + const [error, setError] = useState(null); + const [saved, setSaved] = useState(false); + const [hasChanges, setHasChanges] = useState(false); + const [isFullscreen, setIsFullscreen] = useState(false); + const [diagnostics, setDiagnostics] = useState([]); + const [showDiagnostics, setShowDiagnostics] = useState(true); + const [theme, setTheme] = useState<'vs-dark-plus' | 'vs-dark' | 'vs' | 'hc-black'>('vs-dark-plus'); + const [fontSize, setFontSize] = useState(14); + const [minimap, setMinimap] = useState(true); + const [wordWrap, setWordWrap] = useState<'on' | 'off'>('on'); + const [autoSave, setAutoSave] = useState(false); + + const editorRef = useRef(null); + const monacoRef = useRef(null); + const autoSaveTimerRef = useRef(null); + + const fileName = filePath.split("/").pop() || filePath; + const language = getLanguageFromPath(filePath); + + // 加载文件内容 + const loadFile = useCallback(async () => { + if (!filePath) return; + + try { + setLoading(true); + setError(null); + + const fileContent = await invoke("read_file", { + path: filePath, + }); + + setContent(fileContent); + setOriginalContent(fileContent); + setHasChanges(false); + } catch (err) { + console.error("Failed to load file:", err); + setError(err instanceof Error ? err.message : "Failed to load file"); + } finally { + setLoading(false); + } + }, [filePath]); + + // 保存文件 + const saveFile = useCallback(async () => { + if (!filePath || !hasChanges) return; + + try { + setSaving(true); + setError(null); + + await invoke("write_file", { + path: filePath, + content: content, + }); + + setOriginalContent(content); + setHasChanges(false); + setSaved(true); + + // 显示保存成功提示 + setTimeout(() => setSaved(false), 2000); + } catch (err) { + console.error("Failed to save file:", err); + setError(err instanceof Error ? err.message : "Failed to save file"); + } finally { + setSaving(false); + } + }, [filePath, content, hasChanges]); + + // 自动保存 + useEffect(() => { + if (autoSave && hasChanges) { + if (autoSaveTimerRef.current) { + clearTimeout(autoSaveTimerRef.current); + } + + autoSaveTimerRef.current = setTimeout(() => { + saveFile(); + }, 2000); + } + + return () => { + if (autoSaveTimerRef.current) { + clearTimeout(autoSaveTimerRef.current); + } + }; + }, [autoSave, hasChanges, saveFile]); + + // 处理内容变化 + const handleContentChange = (value: string | undefined) => { + if (value !== undefined) { + setContent(value); + setHasChanges(value !== originalContent); + + // 触发语法检查 + if (editorRef.current && (language === 'typescript' || language === 'javascript')) { + validateCode(value); + } + } + }; + + // 验证代码 + const validateCode = async (_code: string) => { + if (!monacoRef.current || !editorRef.current) return; + + const model = editorRef.current.getModel(); + if (!model) return; + + // 获取 Monaco 的内置诊断 + const markers = monacoRef.current.editor.getModelMarkers({ resource: model.uri }); + + const newDiagnostics: DiagnosticInfo[] = markers.map(marker => ({ + line: marker.startLineNumber, + column: marker.startColumn, + message: marker.message, + severity: marker.severity === 8 ? 'error' : + marker.severity === 4 ? 'warning' : 'info', + source: marker.source || 'typescript' + })); + + setDiagnostics(newDiagnostics); + }; + + // 格式化代码 + const handleFormat = () => { + if (editorRef.current) { + formatDocument(editorRef.current); + } + }; + + // 处理关闭 + const handleClose = () => { + if (hasChanges) { + if (confirm(t("app.unsavedChangesConfirm"))) { + onClose(); + } + } else { + onClose(); + } + }; + + // 切换全屏 + const toggleFullscreen = () => { + setIsFullscreen(!isFullscreen); + }; + + // Monaco Editor 挂载时的处理 + const handleEditorDidMount = (editor: monaco.editor.IStandaloneCodeEditor, monaco: Monaco) => { + editorRef.current = editor; + monacoRef.current = monaco; + + // 初始化 Monaco 配置 + initializeMonaco(); + + // 设置实时语法检查 + setupRealtimeLinting(editor, { + enabled: true, + delay: 500, + showInlineErrors: true, + showErrorsInScrollbar: true, + showErrorsInMinimap: true, + }); + + // 设置快捷键 + editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => { + saveFile(); + }); + + editor.addCommand(monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF, () => { + handleFormat(); + }); + + // 监听光标位置变化 + editor.onDidChangeCursorPosition(() => { + // 可以在这里更新状态栏信息 + }); + + // 初始验证 + if (language === 'typescript' || language === 'javascript') { + setTimeout(() => validateCode(content), 1000); + } + }; + + // 快捷键处理 + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + // Ctrl/Cmd + S 保存 + if ((e.ctrlKey || e.metaKey) && e.key === "s") { + e.preventDefault(); + saveFile(); + } + + // Ctrl/Cmd + Shift + F 格式化 + if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === "f") { + e.preventDefault(); + handleFormat(); + } + + // F11 全屏 + if (e.key === "F11") { + e.preventDefault(); + toggleFullscreen(); + } + + // Esc 退出全屏 + if (e.key === "Escape" && isFullscreen) { + setIsFullscreen(false); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [hasChanges, saveFile, isFullscreen]); + + // 加载文件 + useEffect(() => { + if (filePath) { + loadFile(); + } + }, [filePath, loadFile]); + + // 计算诊断统计 + const diagnosticStats = { + errors: diagnostics.filter(d => d.severity === 'error').length, + warnings: diagnostics.filter(d => d.severity === 'warning').length, + infos: diagnostics.filter(d => d.severity === 'info').length, + }; + + return ( +
+ {/* Header */} +
+
+ +
+ {fileName} + ({language}) + {hasChanges && ( + + {t("app.modified")} + + )} + + {saved && ( + + + {t("app.saved")} + + )} + +
+
+ +
+ {/* 诊断信息 */} + {showDiagnostics && diagnostics.length > 0 && ( +
+ {diagnosticStats.errors > 0 && ( + + + {diagnosticStats.errors} + + )} + {diagnosticStats.warnings > 0 && ( + + + {diagnosticStats.warnings} + + )} + {diagnosticStats.infos > 0 && ( + + + {diagnosticStats.infos} + + )} +
+ )} + + {/* 自动保存指示器 */} + {autoSave && ( + + + +
+ + Auto +
+
+ +

自动保存已启用

+
+
+
+ )} + + {/* 格式化按钮 */} + + + + + + +

格式化代码 (Alt+Shift+F)

+
+
+
+ + {/* 设置菜单 */} + + + + + + setTheme('vs-dark-plus')}> + 主题: VS Dark+ + + setTheme('vs-dark')}> + 主题: VS Dark + + setTheme('vs')}> + 主题: VS Light + + + setFontSize(fontSize + 1)}> + 字体放大 + + setFontSize(fontSize - 1)}> + 字体缩小 + + + setMinimap(!minimap)}> + {minimap ? '隐藏' : '显示'}小地图 + + setWordWrap(wordWrap === 'on' ? 'off' : 'on')}> + {wordWrap === 'on' ? '关闭' : '开启'}自动换行 + + setShowDiagnostics(!showDiagnostics)}> + {showDiagnostics ? '隐藏' : '显示'}诊断信息 + + + setAutoSave(!autoSave)}> + {autoSave ? '关闭' : '开启'}自动保存 + + + + + {/* 保存按钮 */} + {hasChanges && ( + + )} + + {/* 全屏按钮 */} + + + + + + +

{isFullscreen ? '退出全屏 (Esc)' : '全屏 (F11)'}

+
+
+
+ + {/* 关闭按钮 */} + +
+
+ + {/* 诊断面板 */} + {showDiagnostics && diagnostics.length > 0 && ( +
+
+ {diagnostics.map((diagnostic, index) => ( +
{ + // 跳转到错误位置 + if (editorRef.current) { + editorRef.current.setPosition({ + lineNumber: diagnostic.line, + column: diagnostic.column + }); + editorRef.current.focus(); + } + }} + > + {diagnostic.severity === 'error' && } + {diagnostic.severity === 'warning' && } + {diagnostic.severity === 'info' && } + + [{diagnostic.line}:{diagnostic.column}] {diagnostic.message} + + {diagnostic.source && ( + ({diagnostic.source}) + )} +
+ ))} +
+
+ )} + + {/* Editor */} + {error ? ( +
+ +

{t("app.error")}

+

{error}

+
+ ) : loading ? ( +
+ +
+ ) : ( +
+ +
+ )} + + {/* 状态栏 */} +
+
+ {language.toUpperCase()} + UTF-8 + LF +
+
+ Ln 1, Col 1 + Spaces: 2 +
+
+
+ ); +}; + +export default FileEditorEnhanced; \ No newline at end of file diff --git a/src/components/FileExplorerPanel.tsx b/src/components/FileExplorerPanel.tsx new file mode 100644 index 0000000..57fbf98 --- /dev/null +++ b/src/components/FileExplorerPanel.tsx @@ -0,0 +1,584 @@ +import React, { useState, useEffect, useCallback, useMemo } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { invoke } from "@tauri-apps/api/core"; +import { listen, type UnlistenFn } from "@tauri-apps/api/event"; +import { + Folder, + FolderOpen, + File, + FileText, + FileCode, + FileJson, + FileImage, + Search, + ChevronRight, + ChevronDown, + X, + RefreshCw, + Loader2, + AlertCircle, +} from "lucide-react"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { cn } from "@/lib/utils"; +import { useTranslation } from "react-i18next"; +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuTrigger, +} from "@/components/ui/context-menu"; + +interface FileNode { + name: string; + path: string; + file_type: "file" | "directory"; + children?: FileNode[]; + size?: number; + modified?: number; + expanded?: boolean; +} + +interface FileExplorerPanelProps { + projectPath: string; + isVisible: boolean; + onFileSelect?: (path: string) => void; + onFileOpen?: (path: string) => void; + onToggle: () => void; + width?: number; + className?: string; +} + +// 获取文件图标 +const getFileIcon = (filename: string) => { + const ext = filename.split(".").pop()?.toLowerCase(); + + const iconMap: Record = { + // 代码文件 + ts: , + tsx: , + js: , + jsx: , + py: , + rs: , + go: , + java: , + cpp: , + c: , + + // 配置文件 + json: , + yaml: , + yml: , + toml: , + xml: , + + // 文档文件 + md: , + txt: , + pdf: , + + // 图片文件 + png: , + jpg: , + jpeg: , + gif: , + svg: , + ico: , + }; + + return iconMap[ext || ""] || ; +}; + +export const FileExplorerPanel: React.FC = ({ + projectPath, + isVisible, + onFileSelect, + onFileOpen, + onToggle, + width = 280, + className, +}) => { + const { t } = useTranslation(); + const [fileTree, setFileTree] = useState(null); + const [expandedNodes, setExpandedNodes] = useState>(new Set()); + const [searchQuery, setSearchQuery] = useState(""); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [searchResults, setSearchResults] = useState([]); + const [isSearching, setIsSearching] = useState(false); + + // 文件点击处理状态 + const [lastClickTime, setLastClickTime] = useState(0); + const [lastClickPath, setLastClickPath] = useState(null); + + // 键盘导航状态 + const [selectedPath, setSelectedPath] = useState(null); + const [flattenedNodes, setFlattenedNodes] = useState([]); + + const unlistenRef = React.useRef(null); + + // 切换节点展开状态 + const toggleExpand = useCallback((path: string) => { + setExpandedNodes((prev) => { + const next = new Set(prev); + if (next.has(path)) { + next.delete(path); + } else { + next.add(path); + } + return next; + }); + }, []); + + // 打开文件 + const handleOpenFile = useCallback((node: FileNode) => { + if (node.file_type === "file") { + if (onFileOpen) { + onFileOpen(node.path); + } + } + }, [onFileOpen]); + + // 扁平化文件树以支持键盘导航 + const flattenTree = useCallback((node: FileNode, result: FileNode[] = []): FileNode[] => { + result.push(node); + if (node.file_type === "directory" && expandedNodes.has(node.path) && node.children) { + node.children.forEach(child => flattenTree(child, result)); + } + return result; + }, [expandedNodes]); + + // 更新扁平化节点列表 + useEffect(() => { + if (fileTree) { + const flattened = flattenTree(fileTree); + setFlattenedNodes(flattened); + // 如果没有选中的节点,选中第一个 + if (!selectedPath && flattened.length > 0) { + setSelectedPath(flattened[0].path); + } + } + }, [fileTree, expandedNodes, flattenTree, selectedPath]); + + // 键盘导航处理 + useEffect(() => { + if (!isVisible) return; + + const handleKeyDown = (e: KeyboardEvent) => { + if (!selectedPath || flattenedNodes.length === 0) return; + + const currentIndex = flattenedNodes.findIndex(node => node.path === selectedPath); + if (currentIndex === -1) return; + + const currentNode = flattenedNodes[currentIndex]; + + switch (e.key) { + case "ArrowUp": + e.preventDefault(); + if (currentIndex > 0) { + setSelectedPath(flattenedNodes[currentIndex - 1].path); + } + break; + + case "ArrowDown": + e.preventDefault(); + if (currentIndex < flattenedNodes.length - 1) { + setSelectedPath(flattenedNodes[currentIndex + 1].path); + } + break; + + case "ArrowLeft": + e.preventDefault(); + if (currentNode.file_type === "directory" && expandedNodes.has(currentNode.path)) { + // 收起文件夹 + toggleExpand(currentNode.path); + } else { + // 移动到父文件夹 + const parentPath = currentNode.path.substring(0, currentNode.path.lastIndexOf("/")); + const parentNode = flattenedNodes.find(node => node.path === parentPath); + if (parentNode) { + setSelectedPath(parentNode.path); + } + } + break; + + case "ArrowRight": + e.preventDefault(); + if (currentNode.file_type === "directory") { + if (!expandedNodes.has(currentNode.path)) { + // 展开文件夹 + toggleExpand(currentNode.path); + } else if (currentNode.children && currentNode.children.length > 0) { + // 移动到第一个子节点 + setSelectedPath(currentNode.children[0].path); + } + } else { + // 打开文件 + handleOpenFile(currentNode); + } + break; + + case "Enter": + e.preventDefault(); + if (currentNode.file_type === "directory") { + toggleExpand(currentNode.path); + } else { + handleOpenFile(currentNode); + } + break; + + case " ": // Space key + e.preventDefault(); + if (currentNode.file_type === "file") { + // 添加到聊天 + onFileSelect?.(currentNode.path); + } + break; + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [isVisible, selectedPath, flattenedNodes, expandedNodes, toggleExpand, onFileSelect, handleOpenFile]); + + // 加载文件树 + const loadFileTree = useCallback(async () => { + if (!projectPath) return; + + try { + setLoading(true); + setError(null); + + const tree = await invoke("read_directory_tree", { + path: projectPath, + maxDepth: 5, + ignorePatterns: [ + "node_modules", + ".git", + "target", + "dist", + "build", + ".idea", + ".vscode", + "__pycache__", + ".DS_Store", + ], + }); + + setFileTree(tree); + + // 默认展开根目录 + if (tree) { + setExpandedNodes(new Set([tree.path])); + } + } catch (err) { + console.error("Failed to load file tree:", err); + setError(err instanceof Error ? err.message : "Failed to load file tree"); + } finally { + setLoading(false); + } + }, [projectPath]); + + // 搜索文件 + const searchFiles = useCallback(async (query: string) => { + if (!projectPath || !query) { + setSearchResults([]); + return; + } + + try { + setIsSearching(true); + const results = await invoke("search_files_by_name", { + basePath: projectPath, + query, + maxResults: 50, + }); + setSearchResults(results); + } catch (err) { + console.error("Failed to search files:", err); + } finally { + setIsSearching(false); + } + }, [projectPath]); + + // 防抖搜索 + useEffect(() => { + const timer = setTimeout(() => { + if (searchQuery) { + searchFiles(searchQuery); + } else { + setSearchResults([]); + } + }, 300); + + return () => clearTimeout(timer); + }, [searchQuery, searchFiles]); + + // 监听文件系统变化 + useEffect(() => { + if (!projectPath || !isVisible) return; + + const setupListener = async () => { + try { + // 监听文件系统变化事件 + unlistenRef.current = await listen("file-system-change", (event) => { + console.log("File system changed:", event.payload); + loadFileTree(); + }); + + // 启动目录监听 + await invoke("watch_directory", { path: projectPath }); + } catch (err) { + console.error("Failed to setup file watcher:", err); + } + }; + + setupListener(); + loadFileTree(); + + return () => { + if (unlistenRef.current) { + unlistenRef.current(); + unlistenRef.current = null; + } + }; + }, [projectPath, isVisible, loadFileTree]); + + // 处理文件选择 + const handleFileClick = useCallback((node: FileNode) => { + // 设置选中状态 + setSelectedPath(node.path); + + if (node.file_type === "directory") { + toggleExpand(node.path); + } else { + const now = Date.now(); + const timeDiff = now - lastClickTime; + + // 检测双击(300ms内的两次点击) + if (lastClickPath === node.path && timeDiff < 300) { + // 双击 - 添加到提及 + onFileSelect?.(node.path); + // 重置状态 + setLastClickTime(0); + setLastClickPath(null); + } else { + // 单击 - 打开文件 + handleOpenFile(node); + setLastClickTime(now); + setLastClickPath(node.path); + } + } + }, [onFileSelect, toggleExpand, lastClickTime, lastClickPath, handleOpenFile]); + + // 复制路径到剪贴板 + const copyPath = useCallback(async (path: string) => { + await navigator.clipboard.writeText(path); + }, []); + + // 渲染文件树节点 + const renderNode = useCallback((node: FileNode, depth = 0): React.ReactNode => { + const isExpanded = expandedNodes.has(node.path); + const hasChildren = node.children && node.children.length > 0; + const isSelected = selectedPath === node.path; + + return ( +
+ + +
handleFileClick(node)} + > + {node.file_type === "directory" ? ( + <> + {hasChildren && ( +
+ {isExpanded ? ( + + ) : ( + + )} +
+ )} + {!hasChildren &&
} +
+ {isExpanded ? ( + + ) : ( + + )} +
+ + ) : ( + <> +
+
{getFileIcon(node.name)}
+ + )} + {node.name} +
+ + + + copyPath(node.path)}> + {t('app.copyPath')} + + {node.file_type === "file" && ( + <> + handleOpenFile(node)}> + {t('app.openFile')} + + onFileSelect?.(node.path)}> + {t('app.addToChat')} + + + )} + + + + {isExpanded && node.children && ( +
+ {node.children.map((child) => renderNode(child, depth + 1))} +
+ )} +
+ ); + }, [expandedNodes, handleFileClick, copyPath, onFileSelect, onFileOpen, selectedPath, handleOpenFile]); + + // 渲染搜索结果 + const renderSearchResults = useMemo(() => { + if (!searchQuery || searchResults.length === 0) return null; + + return ( +
+
+ {searchResults.length > 0 + ? `Found ${searchResults.length} results` + : t('app.noFilesFound')} +
+
+ {searchResults.map((path) => { + const filename = path.split("/").pop() || path; + const relativePath = path.replace(projectPath + "/", ""); + + return ( +
onFileSelect?.(path)} + > +
+ {getFileIcon(filename)} + {relativePath} +
+
+ ); + })} +
+
+ ); + }, [searchQuery, searchResults, projectPath, onFileSelect]); + + return ( + <> + + {isVisible && ( + +
+ {/* Header */} +
+
+
+ + {t('app.fileExplorer')} +
+
+ + +
+
+ + {/* Search */} +
+ + setSearchQuery(e.target.value)} + className="h-7 pl-7 text-xs" + /> + {isSearching && ( + + )} +
+
+ + {/* File Tree or Search Results */} + + {error ? ( +
+ +

{error}

+
+ ) : loading ? ( +
+ +
+ ) : ( + <> + {renderSearchResults} + {!searchQuery && fileTree && ( +
+ {renderNode(fileTree)} +
+ )} + + )} +
+
+
+ )} +
+ + ); +}; + +// Add default export +export default FileExplorerPanel; diff --git a/src/components/FileViewer.tsx b/src/components/FileViewer.tsx new file mode 100644 index 0000000..fa195ac --- /dev/null +++ b/src/components/FileViewer.tsx @@ -0,0 +1,364 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { invoke } from "@tauri-apps/api/core"; +import { + X, + Save, + FileText, + AlertCircle, + Check, + Edit3, + Eye, + Loader2 +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { useTranslation } from "react-i18next"; +import Editor from "@monaco-editor/react"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; + +interface FileViewerProps { + filePath: string; + isVisible: boolean; + onClose: () => void; + className?: string; +} + +// 根据文件扩展名获取语言 +const getLanguageFromPath = (path: string): string => { + const ext = path.split(".").pop()?.toLowerCase(); + + const languageMap: Record = { + // JavaScript/TypeScript + js: "javascript", + jsx: "javascript", + ts: "typescript", + tsx: "typescript", + + // Web + html: "html", + htm: "html", + css: "css", + scss: "scss", + sass: "sass", + less: "less", + + // Programming Languages + py: "python", + java: "java", + c: "c", + cpp: "cpp", + cc: "cpp", + cxx: "cpp", + cs: "csharp", + php: "php", + rb: "ruby", + go: "go", + rs: "rust", + kt: "kotlin", + swift: "swift", + m: "objective-c", + scala: "scala", + sh: "shell", + bash: "shell", + zsh: "shell", + fish: "shell", + ps1: "powershell", + r: "r", + lua: "lua", + perl: "perl", + + // Data/Config + json: "json", + xml: "xml", + yaml: "yaml", + yml: "yaml", + toml: "toml", + ini: "ini", + cfg: "ini", + conf: "ini", + + // Documentation + md: "markdown", + markdown: "markdown", + rst: "restructuredtext", + tex: "latex", + + // Database + sql: "sql", + + // Others + dockerfile: "dockerfile", + makefile: "makefile", + cmake: "cmake", + gradle: "gradle", + }; + + return languageMap[ext || ""] || "plaintext"; +}; + +export const FileViewer: React.FC = ({ + filePath, + isVisible, + onClose, + className, +}) => { + const { t } = useTranslation(); + const [content, setContent] = useState(""); + const [originalContent, setOriginalContent] = useState(""); + const [isEditing, setIsEditing] = useState(false); + const [loading, setLoading] = useState(false); + const [saving, setSaving] = useState(false); + const [error, setError] = useState(null); + const [saved, setSaved] = useState(false); + const [hasChanges, setHasChanges] = useState(false); + + const fileName = filePath.split("/").pop() || filePath; + const language = getLanguageFromPath(filePath); + + // 加载文件内容 + const loadFile = useCallback(async () => { + if (!filePath) return; + + try { + setLoading(true); + setError(null); + + const fileContent = await invoke("read_file", { + path: filePath, + }); + + setContent(fileContent); + setOriginalContent(fileContent); + setHasChanges(false); + } catch (err) { + console.error("Failed to load file:", err); + setError(err instanceof Error ? err.message : "Failed to load file"); + } finally { + setLoading(false); + } + }, [filePath]); + + // 保存文件 + const saveFile = useCallback(async () => { + if (!filePath || !hasChanges) return; + + try { + setSaving(true); + setError(null); + + await invoke("write_file", { + path: filePath, + content: content, + }); + + setOriginalContent(content); + setHasChanges(false); + setSaved(true); + + // 显示保存成功提示 + setTimeout(() => setSaved(false), 2000); + } catch (err) { + console.error("Failed to save file:", err); + setError(err instanceof Error ? err.message : "Failed to save file"); + } finally { + setSaving(false); + } + }, [filePath, content, hasChanges]); + + // 处理内容变化 + const handleContentChange = (value: string | undefined) => { + if (value !== undefined) { + setContent(value); + setHasChanges(value !== originalContent); + } + }; + + // 处理关闭 + const handleClose = () => { + if (hasChanges) { + if (confirm(t("app.unsavedChangesConfirm"))) { + onClose(); + } + } else { + onClose(); + } + }; + + // 切换编辑模式 + const toggleEditMode = () => { + setIsEditing(!isEditing); + }; + + // 快捷键处理 + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + // Ctrl/Cmd + S 保存 + if ((e.ctrlKey || e.metaKey) && e.key === "s" && isEditing && hasChanges) { + e.preventDefault(); + saveFile(); + } + // Esc 退出编辑模式 + if (e.key === "Escape" && isEditing) { + setIsEditing(false); + } + }; + + if (isVisible) { + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + } + }, [isVisible, isEditing, hasChanges, saveFile]); + + // 加载文件 + useEffect(() => { + if (isVisible && filePath) { + loadFile(); + } + }, [isVisible, filePath, loadFile]); + + return ( + + {isVisible && ( + + e.stopPropagation()} + > + {/* Header */} +
+
+ +
+

{fileName}

+

{filePath}

+
+ {hasChanges && ( + + {t("app.modified")} + + )} + {saved && ( + + + {t("app.saved")} + + )} +
+ +
+ + + + + + +

{isEditing ? t("app.viewMode") : t("app.editMode")}

+
+
+
+ + {isEditing && hasChanges && ( + + )} + + +
+
+ + {/* Content */} + {error ? ( +
+ +

{t("app.error")}

+

{error}

+
+ ) : loading ? ( +
+ +
+ ) : ( +
+ +
+ )} +
+
+ )} +
+ ); +}; + +export default FileViewer; \ No newline at end of file diff --git a/src/components/GitPanel.tsx b/src/components/GitPanel.tsx new file mode 100644 index 0000000..798a5e0 --- /dev/null +++ b/src/components/GitPanel.tsx @@ -0,0 +1,582 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { invoke } from "@tauri-apps/api/core"; +import { + GitBranch, + GitCommit, + GitMerge, + GitPullRequest, + FileText, + FilePlus, + FileMinus, + FileEdit, + X, + RefreshCw, + Loader2, + AlertCircle, + CheckCircle, + Circle, +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Badge } from "@/components/ui/badge"; +import { cn } from "@/lib/utils"; +import { useTranslation } from "react-i18next"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; + +interface GitStatus { + branch: string; + ahead: number; + behind: number; + staged: GitFileStatus[]; + modified: GitFileStatus[]; + untracked: GitFileStatus[]; + conflicted: GitFileStatus[]; + is_clean: boolean; + remote_url?: string; +} + +interface GitFileStatus { + path: string; + status: string; + staged: boolean; +} + +interface GitCommitInfo { + hash: string; + short_hash: string; + author: string; + email: string; + date: string; + message: string; + files_changed: number; + insertions: number; + deletions: number; +} + +interface GitBranchInfo { + name: string; + is_current: boolean; + remote?: string; + last_commit?: string; +} + +interface GitPanelProps { + projectPath: string; + isVisible: boolean; + onToggle: () => void; + width?: number; + className?: string; + refreshInterval?: number; +} + +// 获取文件状态图标 +const getFileStatusIcon = (status: string) => { + switch (status) { + case "added": + return ; + case "modified": + return ; + case "deleted": + return ; + case "renamed": + return ; + case "untracked": + return ; + case "conflicted": + return ; + default: + return ; + } +}; + +// 格式化日期 +const formatDate = (dateStr: string, t: (key: string, opts?: any) => string) => { + const date = new Date(dateStr); + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + const hours = Math.floor(diff / (1000 * 60 * 60)); + const minutes = Math.floor(diff / (1000 * 60)); + + if (days > 7) { + return date.toLocaleDateString(); + } else if (days > 0) { + return t('app.daysAgo', { count: days }); + } else if (hours > 0) { + return t('app.hoursAgo', { count: hours }); + } else if (minutes > 0) { + return t('app.minutesAgo', { count: minutes }); + } else { + return t('app.justNow'); + } +}; + +export const GitPanel: React.FC = ({ + projectPath, + isVisible, + onToggle, + width = 320, + className, + refreshInterval = 5000, +}) => { + const { t } = useTranslation(); + const [gitStatus, setGitStatus] = useState(null); + const [commits, setCommits] = useState([]); + const [branches, setBranches] = useState([]); + const [selectedTab, setSelectedTab] = useState<"status" | "history" | "branches">("status"); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [isRefreshing, setIsRefreshing] = useState(false); + + // 获取 Git 状态 + const fetchGitStatus = useCallback(async () => { + if (!projectPath) return; + + try { + setError(null); + const status = await invoke("get_git_status", { + path: projectPath, + }); + setGitStatus(status); + } catch (err) { + console.error("Failed to fetch git status:", err); + setError(err instanceof Error ? err.message : "Failed to fetch git status"); + setGitStatus(null); + } + }, [projectPath]); + + // 获取提交历史 + const fetchCommitHistory = useCallback(async () => { + if (!projectPath) return; + + try { + const history = await invoke("get_git_history", { + path: projectPath, + limit: 50, + }); + setCommits(history); + } catch (err) { + console.error("Failed to fetch commit history:", err); + } + }, [projectPath]); + + // 获取分支列表 + const fetchBranches = useCallback(async () => { + if (!projectPath) return; + + try { + const branchList = await invoke("get_git_branches", { + path: projectPath, + }); + setBranches(branchList); + } catch (err) { + console.error("Failed to fetch branches:", err); + } + }, [projectPath]); + + // 刷新所有数据 + const refreshAll = useCallback(async () => { + setIsRefreshing(true); + await Promise.all([ + fetchGitStatus(), + fetchCommitHistory(), + fetchBranches(), + ]); + setIsRefreshing(false); + }, [fetchGitStatus, fetchCommitHistory, fetchBranches]); + + // 初始加载和定时刷新 + useEffect(() => { + if (!projectPath || !isVisible) return; + + setLoading(true); + refreshAll().finally(() => setLoading(false)); + + // 定时刷新状态 + const interval = setInterval(() => { + fetchGitStatus(); + }, refreshInterval); + + return () => clearInterval(interval); + }, [projectPath, isVisible, refreshInterval, refreshAll, fetchGitStatus]); + + // 渲染状态视图 + const renderStatusView = () => { + if (!gitStatus) { + return ( +
+ +

{t('app.noGitRepository')}

+
+ ); + } + + return ( +
+ {/* Branch Info */} +
+
+
+ + {gitStatus.branch} +
+
+ {gitStatus.ahead > 0 && ( + + ↑ {gitStatus.ahead} + + )} + {gitStatus.behind > 0 && ( + + ↓ {gitStatus.behind} + + )} +
+
+ {gitStatus.remote_url && ( +

+ {gitStatus.remote_url} +

+ )} +
+ + {/* Status Summary */} + {gitStatus.is_clean ? ( +
+ + {t('app.workingTreeClean')} +
+ ) : ( +
+ {gitStatus.staged.length > 0 && ( +
+

+ {t('app.staged')} ({gitStatus.staged.length}) +

+ {gitStatus.staged.map((file) => ( +
+ {getFileStatusIcon(file.status)} + {file.path} +
+ ))} +
+ )} + + {gitStatus.modified.length > 0 && ( +
+

+ {t('app.modified')} ({gitStatus.modified.length}) +

+ {gitStatus.modified.map((file) => ( +
+ {getFileStatusIcon(file.status)} + {file.path} +
+ ))} +
+ )} + + {gitStatus.untracked.length > 0 && ( +
+

+ {t('app.untracked')} ({gitStatus.untracked.length}) +

+ {gitStatus.untracked.slice(0, 10).map((file) => ( +
+ {getFileStatusIcon(file.status)} + {file.path} +
+ ))} + {gitStatus.untracked.length > 10 && ( +

+ {t('app.andMore', { count: gitStatus.untracked.length - 10 })} +

+ )} +
+ )} + + {gitStatus.conflicted.length > 0 && ( +
+

+ {t('app.conflicted')} ({gitStatus.conflicted.length}) +

+ {gitStatus.conflicted.map((file) => ( +
+ {getFileStatusIcon(file.status)} + {file.path} +
+ ))} +
+ )} +
+ )} +
+ ); + }; + + // 渲染历史视图 + const renderHistoryView = () => { + if (commits.length === 0) { + return ( +
+ +

{t('app.noCommitsFound')}

+
+ ); + } + + return ( +
+ {commits.map((commit) => ( +
+
+
+

+ {commit.message} +

+
+ + {commit.short_hash} + + + + {commit.author} + +
+
+ + {formatDate(commit.date, t)} + + {commit.files_changed > 0 && ( + <> + +
+ {commit.files_changed} {t('app.filesChanged')} + +{commit.insertions} + -{commit.deletions} +
+ + )} +
+
+
+
+ ))} +
+ ); + }; + + // 渲染分支视图 + const renderBranchesView = () => { + if (branches.length === 0) { + return ( +
+ +

{t('app.noBranchesFound')}

+
+ ); + } + + const localBranches = branches.filter(b => !b.remote); + const remoteBranches = branches.filter(b => b.remote); + + return ( +
+ {localBranches.length > 0 && ( +
+

+ {t('app.localBranches')} +

+ {localBranches.map((branch) => ( +
+
+ + {branch.name} + {branch.is_current && ( + + {t('app.current')} + + )} +
+ {branch.last_commit && ( + + {branch.last_commit.slice(0, 7)} + + )} +
+ ))} +
+ )} + + {remoteBranches.length > 0 && ( +
+

+ {t('app.remoteBranches')} +

+ {remoteBranches.map((branch) => ( +
+
+ + + {branch.name} + +
+ {branch.last_commit && ( + + {branch.last_commit.slice(0, 7)} + + )} +
+ ))} +
+ )} +
+ ); + }; + + return ( + + {isVisible && ( + +
+ {/* Header */} +
+
+
+ + {t('app.gitPanel')} +
+
+ + + + + + +

{t('app.refresh')}

+
+
+
+ +
+
+
+ + {/* Tabs */} + setSelectedTab(v as typeof selectedTab)} + className="flex-1 flex flex-col" + > + + + {t('app.gitStatus')} + + + {t('app.gitHistory')} + + + {t('app.gitBranches')} + + + + {error ? ( +
+ +

{error}

+
+ ) : loading ? ( +
+ +
+ ) : ( + <> + + + {renderStatusView()} + + + + + + {renderHistoryView()} + + + + + + {renderBranchesView()} + + + + )} +
+
+
+ )} +
+ ); +}; + +// Add default export +export default GitPanel; diff --git a/src/components/ui/context-menu.tsx b/src/components/ui/context-menu.tsx new file mode 100644 index 0000000..3e2009b --- /dev/null +++ b/src/components/ui/context-menu.tsx @@ -0,0 +1,192 @@ +import * as React from "react" +import * as ContextMenuPrimitive from "@radix-ui/react-context-menu" +import { Check, ChevronRight, Circle } from "lucide-react" +import { cn } from "@/lib/utils" + +const ContextMenu = ContextMenuPrimitive.Root +const ContextMenuTrigger = ContextMenuPrimitive.Trigger +const ContextMenuGroup = ContextMenuPrimitive.Group +const ContextMenuPortal = ContextMenuPrimitive.Portal +const ContextMenuSub = ContextMenuPrimitive.Sub +const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup + +const ContextMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName + +const ContextMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName + +const ContextMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName + +const ContextMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName + +const ContextMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +ContextMenuCheckboxItem.displayName = + ContextMenuPrimitive.CheckboxItem.displayName + +const ContextMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName + +const ContextMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName + +const ContextMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName + +const ContextMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +ContextMenuShortcut.displayName = "ContextMenuShortcut" + +export { + ContextMenu, + ContextMenuTrigger, + ContextMenuContent, + ContextMenuItem, + ContextMenuCheckboxItem, + ContextMenuRadioItem, + ContextMenuLabel, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuGroup, + ContextMenuPortal, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuRadioGroup, +} \ No newline at end of file diff --git a/src/lib/eslint-integration.ts b/src/lib/eslint-integration.ts new file mode 100644 index 0000000..265260a --- /dev/null +++ b/src/lib/eslint-integration.ts @@ -0,0 +1,219 @@ +import * as monaco from 'monaco-editor'; +import type { Linter } from 'eslint'; + +// 将 ESLint 诊断转换为 Monaco 标记 +export function convertESLintToMonacoMarkers( + eslintMessages: Linter.LintMessage[], + _model: monaco.editor.ITextModel +): monaco.editor.IMarkerData[] { + return eslintMessages.map(message => { + return { + severity: message.severity === 2 + ? monaco.MarkerSeverity.Error + : monaco.MarkerSeverity.Warning, + startLineNumber: message.line || 1, + startColumn: message.column || 1, + endLineNumber: message.endLine || message.line || 1, + endColumn: message.endColumn || (message.column ? message.column + 1 : 1), + message: message.message, + source: message.ruleId || 'eslint', + }; + }); +} + +// 实时语法检查配置 +export interface RealtimeLintOptions { + enabled: boolean; + delay: number; // 延迟时间(毫秒) + showInlineErrors: boolean; + showErrorsInScrollbar: boolean; + showErrorsInMinimap: boolean; +} + +export const defaultLintOptions: RealtimeLintOptions = { + enabled: true, + delay: 500, + showInlineErrors: true, + showErrorsInScrollbar: true, + showErrorsInMinimap: true, +}; + +// 配置实时语法检查 +export function setupRealtimeLinting( + editor: monaco.editor.IStandaloneCodeEditor, + options: RealtimeLintOptions = defaultLintOptions +) { + if (!options.enabled) return; + + let lintTimer: NodeJS.Timeout | null = null; + + const performLinting = () => { + const model = editor.getModel(); + if (!model) return; + + const language = model.getLanguageId(); + if (language !== 'typescript' && language !== 'javascript' && + language !== 'typescriptreact' && language !== 'javascriptreact') { + return; + } + + // 根据选项配置显示 + if (options.showErrorsInScrollbar) { + editor.updateOptions({ + overviewRulerLanes: 3, + }); + } + + if (options.showErrorsInMinimap) { + editor.updateOptions({ + minimap: { + showSlider: 'always', + renderCharacters: false, + }, + }); + } + }; + + // 监听内容变化 + editor.onDidChangeModelContent(() => { + if (lintTimer) { + clearTimeout(lintTimer); + } + + lintTimer = setTimeout(() => { + performLinting(); + }, options.delay); + }); + + // 初始检查 + performLinting(); +} + +// 代码快速修复建议 +export interface QuickFix { + title: string; + kind: string; + edit: monaco.languages.WorkspaceEdit; +} + +// 注册代码操作提供器(快速修复) +export function registerCodeActionProvider() { + monaco.languages.registerCodeActionProvider(['typescript', 'javascript', 'typescriptreact', 'javascriptreact'], { + provideCodeActions: (model, _range, context, _token) => { + const actions: monaco.languages.CodeAction[] = []; + + // 检查是否有错误标记 + const markers = context.markers.filter(marker => marker.severity === monaco.MarkerSeverity.Error); + + for (const marker of markers) { + // 未使用变量的快速修复 + if (marker.code === '6133' || marker.message.includes('is declared but')) { + actions.push({ + title: `Remove unused declaration`, + kind: 'quickfix', + diagnostics: [marker], + edit: { + edits: [{ + resource: model.uri, + textEdit: { + range: { + startLineNumber: marker.startLineNumber, + startColumn: 1, + endLineNumber: marker.endLineNumber, + endColumn: model.getLineLength(marker.endLineNumber) + 1, + }, + text: '', + }, + versionId: undefined, + }], + }, + isPreferred: true, + }); + } + + // 缺少导入的快速修复 + if (marker.message.includes('Cannot find name')) { + const variableName = marker.message.match(/Cannot find name '([^']+)'/)?.[1]; + if (variableName) { + actions.push({ + title: `Import '${variableName}'`, + kind: 'quickfix', + diagnostics: [marker], + edit: { + edits: [{ + resource: model.uri, + textEdit: { + range: { + startLineNumber: 1, + startColumn: 1, + endLineNumber: 1, + endColumn: 1, + }, + text: `import { ${variableName} } from './${variableName.toLowerCase()}';\n`, + }, + versionId: undefined, + }], + }, + isPreferred: false, + }); + } + } + + // 类型错误的快速修复 + if (marker.message.includes('Type') && marker.message.includes('is not assignable')) { + actions.push({ + title: 'Add type assertion', + kind: 'quickfix', + diagnostics: [marker], + edit: { + edits: [{ + resource: model.uri, + textEdit: { + range: { + startLineNumber: marker.startLineNumber, + startColumn: marker.startColumn, + endLineNumber: marker.endLineNumber, + endColumn: marker.endColumn, + }, + text: `(${model.getValueInRange({ + startLineNumber: marker.startLineNumber, + startColumn: marker.startColumn, + endLineNumber: marker.endLineNumber, + endColumn: marker.endColumn, + })} as any)`, + }, + versionId: undefined, + }], + }, + isPreferred: false, + }); + } + } + + // 添加格式化操作 + actions.push({ + title: 'Format Document', + kind: 'source.formatAll', + command: { + id: 'editor.action.formatDocument', + title: 'Format Document', + }, + }); + + // 添加组织导入操作 + actions.push({ + title: 'Organize Imports', + kind: 'source.organizeImports', + command: { + id: 'editor.action.organizeImports', + title: 'Organize Imports', + }, + }); + + return { + actions, + dispose: () => {}, + }; + }, + }); +} \ No newline at end of file diff --git a/src/lib/monaco-config.ts b/src/lib/monaco-config.ts new file mode 100644 index 0000000..fdad942 --- /dev/null +++ b/src/lib/monaco-config.ts @@ -0,0 +1,412 @@ +import * as monaco from 'monaco-editor'; +import { registerCodeActionProvider } from './eslint-integration'; + +// TypeScript 默认编译选项 +export const defaultCompilerOptions: monaco.languages.typescript.CompilerOptions = { + target: monaco.languages.typescript.ScriptTarget.Latest, + allowNonTsExtensions: true, + moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, + module: monaco.languages.typescript.ModuleKind.ESNext, + noEmit: true, + esModuleInterop: true, + jsx: monaco.languages.typescript.JsxEmit.React, + reactNamespace: 'React', + allowJs: true, + typeRoots: ['node_modules/@types'], + lib: ['es2020', 'dom', 'dom.iterable', 'esnext'], + strict: true, + skipLibCheck: true, + forceConsistentCasingInFileNames: true, + resolveJsonModule: true, + isolatedModules: true, + noUnusedLocals: true, + noUnusedParameters: true, + noImplicitReturns: true, + noFallthroughCasesInSwitch: true, +}; + +// JavaScript 默认编译选项 +export const jsCompilerOptions: monaco.languages.typescript.CompilerOptions = { + ...defaultCompilerOptions, + strict: false, + noUnusedLocals: false, + noUnusedParameters: false, + checkJs: true, + allowJs: true, +}; + +// 配置 TypeScript 语言服务 +export function configureMonacoTypescript() { + // 配置 TypeScript 默认选项 + monaco.languages.typescript.typescriptDefaults.setCompilerOptions(defaultCompilerOptions); + + // 配置 JavaScript 默认选项 + monaco.languages.typescript.javascriptDefaults.setCompilerOptions(jsCompilerOptions); + + // 设置诊断选项 + monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ + noSemanticValidation: false, + noSyntaxValidation: false, + noSuggestionDiagnostics: false, + }); + + monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({ + noSemanticValidation: false, + noSyntaxValidation: false, + noSuggestionDiagnostics: false, + }); + + // 启用格式化选项 + monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true); + monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true); +} + +// 添加常用类型定义 +export async function addTypeDefinitions() { + const typeDefs = [ + { + name: '@types/react', + content: ` +declare module "react" { + export interface ReactElement

= string | JSXElementConstructor> { + type: T; + props: P; + key: Key | null; + } + export type FC

= FunctionComponent

; + export interface FunctionComponent

{ + (props: P, context?: any): ReactElement | null; + } + export function useState(initialState: S | (() => S)): [S, Dispatch>]; + export function useEffect(effect: EffectCallback, deps?: DependencyList): void; + export function useCallback(callback: T, deps: DependencyList): T; + export function useMemo(factory: () => T, deps: DependencyList): T; + export function useRef(initialValue: T): MutableRefObject; +} + ` + }, + { + name: '@types/node', + content: ` +declare module "fs" { + export function readFileSync(path: string, encoding?: string): string | Buffer; + export function writeFileSync(path: string, data: string | Buffer): void; +} +declare module "path" { + export function join(...paths: string[]): string; + export function resolve(...paths: string[]): string; +} + ` + } + ]; + + for (const typeDef of typeDefs) { + monaco.languages.typescript.typescriptDefaults.addExtraLib( + typeDef.content, + `file:///node_modules/${typeDef.name}/index.d.ts` + ); + monaco.languages.typescript.javascriptDefaults.addExtraLib( + typeDef.content, + `file:///node_modules/${typeDef.name}/index.d.ts` + ); + } +} + +// 注册自定义主题 +export function registerCustomThemes() { + // VS Code Dark+ 主题 + monaco.editor.defineTheme('vs-dark-plus', { + base: 'vs-dark', + inherit: true, + rules: [ + { token: 'comment', foreground: '6A9955' }, + { token: 'keyword', foreground: '569CD6' }, + { token: 'string', foreground: 'CE9178' }, + { token: 'number', foreground: 'B5CEA8' }, + { token: 'type', foreground: '4EC9B0' }, + { token: 'class', foreground: '4EC9B0' }, + { token: 'function', foreground: 'DCDCAA' }, + { token: 'variable', foreground: '9CDCFE' }, + { token: 'constant', foreground: '4FC1FF' }, + { token: 'parameter', foreground: '9CDCFE' }, + { token: 'property', foreground: '9CDCFE' }, + { token: 'regexp', foreground: 'D16969' }, + { token: 'operator', foreground: 'D4D4D4' }, + { token: 'namespace', foreground: '4EC9B0' }, + { token: 'type.identifier', foreground: '4EC9B0' }, + { token: 'tag', foreground: '569CD6' }, + { token: 'attribute.name', foreground: '9CDCFE' }, + { token: 'attribute.value', foreground: 'CE9178' }, + ], + colors: { + 'editor.background': '#1E1E1E', + 'editor.foreground': '#D4D4D4', + 'editorLineNumber.foreground': '#858585', + 'editorCursor.foreground': '#AEAFAD', + 'editor.selectionBackground': '#264F78', + 'editor.inactiveSelectionBackground': '#3A3D41', + 'editorIndentGuide.background': '#404040', + 'editorIndentGuide.activeBackground': '#707070', + 'editor.wordHighlightBackground': '#515C6A', + 'editor.wordHighlightStrongBackground': '#515C6A', + 'editorError.foreground': '#F48771', + 'editorWarning.foreground': '#CCA700', + 'editorInfo.foreground': '#75BEFF', + } + }); +} + +// 配置 JSON 语言 +export function configureJsonLanguage() { + monaco.languages.json.jsonDefaults.setDiagnosticsOptions({ + validate: true, + schemas: [ + { + uri: 'http://json-schema.org/draft-07/schema#', + fileMatch: ['*.json'], + schema: { + type: 'object', + properties: {}, + additionalProperties: true + } + }, + { + uri: 'http://json.schemastore.org/package', + fileMatch: ['package.json'], + schema: { + type: 'object', + properties: { + name: { type: 'string' }, + version: { type: 'string' }, + dependencies: { type: 'object' }, + devDependencies: { type: 'object' }, + scripts: { type: 'object' } + } + } + }, + { + uri: 'http://json.schemastore.org/tsconfig', + fileMatch: ['tsconfig.json', 'tsconfig.*.json'], + schema: { + type: 'object', + properties: { + compilerOptions: { type: 'object' }, + include: { type: 'array' }, + exclude: { type: 'array' } + } + } + } + ], + allowComments: true, + trailingCommas: 'warning' + }); +} + +// 添加代码片段 +export function registerSnippets() { + // TypeScript/JavaScript 代码片段 + monaco.languages.registerCompletionItemProvider(['typescript', 'javascript', 'typescriptreact', 'javascriptreact'], { + provideCompletionItems: (model, position) => { + const word = model.getWordUntilPosition(position); + const range = { + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + startColumn: word.startColumn, + endColumn: word.endColumn + }; + + const suggestions = [ + { + label: 'log', + kind: monaco.languages.CompletionItemKind.Snippet, + insertText: 'console.log(${1:message});', + insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, + documentation: 'Console log statement', + range + }, + { + label: 'useState', + kind: monaco.languages.CompletionItemKind.Snippet, + insertText: 'const [${1:state}, set${1/(.*)/${1:/capitalize}/}] = useState(${2:initialValue});', + insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, + documentation: 'React useState hook', + range + }, + { + label: 'useEffect', + kind: monaco.languages.CompletionItemKind.Snippet, + insertText: [ + 'useEffect(() => {', + '\t${1:// Effect logic}', + '\treturn () => {', + '\t\t${2:// Cleanup}', + '\t};', + '}, [${3:dependencies}]);' + ].join('\n'), + insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, + documentation: 'React useEffect hook', + range + }, + { + label: 'component', + kind: monaco.languages.CompletionItemKind.Snippet, + insertText: [ + 'const ${1:ComponentName}: React.FC = () => {', + '\treturn (', + '\t\t

', + '\t\t\t${2:content}', + '\t\t
', + '\t);', + '};', + '', + 'export default ${1:ComponentName};' + ].join('\n'), + insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, + documentation: 'React functional component', + range + }, + { + label: 'async', + kind: monaco.languages.CompletionItemKind.Snippet, + insertText: [ + 'async function ${1:functionName}() {', + '\ttry {', + '\t\tconst result = await ${2:promise};', + '\t\t${3:// Handle result}', + '\t} catch (error) {', + '\t\tconsole.error(error);', + '\t}', + '}' + ].join('\n'), + insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, + documentation: 'Async function with try-catch', + range + } + ]; + + return { suggestions }; + } + }); +} + +// 配置语言特性 +export function configureLanguageFeatures() { + // 配置 HTML 标签自动闭合 + monaco.languages.registerOnTypeFormattingEditProvider(['html', 'xml', 'javascriptreact', 'typescriptreact'], { + autoFormatTriggerCharacters: ['>'], + provideOnTypeFormattingEdits: (model, position, ch) => { + if (ch === '>') { + const lineContent = model.getLineContent(position.lineNumber); + const beforeCursor = lineContent.substring(0, position.column - 1); + + // 检查是否是开始标签 + const tagMatch = beforeCursor.match(/<(\w+)(?:\s+[^>]*)?>/); + if (tagMatch) { + const tagName = tagMatch[1]; + // 自闭合标签列表 + const selfClosingTags = ['img', 'br', 'hr', 'input', 'meta', 'link']; + if (!selfClosingTags.includes(tagName.toLowerCase())) { + return [{ + range: { + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: position.lineNumber, + endColumn: position.column + }, + text: `` + }]; + } + } + } + return []; + } + }); + + // 配置括号自动配对 + monaco.languages.setLanguageConfiguration('typescript', { + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '`', close: '`' }, + { open: '<', close: '>' }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '`', close: '`' }, + { open: '<', close: '>' }, + ], + }); +} + +// 初始化 Monaco Editor 配置 +export async function initializeMonaco() { + // 配置 TypeScript/JavaScript + configureMonacoTypescript(); + + // 添加类型定义 + await addTypeDefinitions(); + + // 注册自定义主题 + registerCustomThemes(); + + // 配置 JSON + configureJsonLanguage(); + + // 注册代码片段 + registerSnippets(); + + // 配置语言特性 + configureLanguageFeatures(); + + // 注册代码操作提供器(快速修复) + registerCodeActionProvider(); +} + +// 格式化文档 +export function formatDocument(editor: monaco.editor.IStandaloneCodeEditor) { + editor.getAction('editor.action.formatDocument')?.run(); +} + +// 添加错误标记 +export function addErrorMarkers( + editor: monaco.editor.IStandaloneCodeEditor, + errors: Array<{ + line: number; + column: number; + message: string; + severity: 'error' | 'warning' | 'info'; + }> +) { + const model = editor.getModel(); + if (!model) return; + + const markers = errors.map(error => ({ + severity: error.severity === 'error' + ? monaco.MarkerSeverity.Error + : error.severity === 'warning' + ? monaco.MarkerSeverity.Warning + : monaco.MarkerSeverity.Info, + startLineNumber: error.line, + startColumn: error.column, + endLineNumber: error.line, + endColumn: error.column + 1, + message: error.message, + })); + + monaco.editor.setModelMarkers(model, 'owner', markers); +} + +// 清除错误标记 +export function clearErrorMarkers(editor: monaco.editor.IStandaloneCodeEditor) { + const model = editor.getModel(); + if (model) { + monaco.editor.setModelMarkers(model, 'owner', []); + } +} \ No newline at end of file