diff --git a/package.json b/package.json index 314ba348..6cda0bce 100644 --- a/package.json +++ b/package.json @@ -35,25 +35,27 @@ }, "devDependencies": { "@codemirror/autocomplete": "^6.20.0", + "@codemirror/collab": "^6.1.1", "@codemirror/commands": "^6.10.1", "@codemirror/lang-javascript": "^6.2.4", - "@codemirror/language": "^6.11.3", + "@codemirror/language": "^6.12.1", + "@codemirror/lint": "^6.9.2", "@codemirror/merge": "^6.11.2", - "@codemirror/state": "^6.5.2", - "@codemirror/view": "^6.39.4", + "@codemirror/state": "^6.5.3", + "@codemirror/view": "^6.39.9", "@fontsource-variable/material-symbols-rounded": "^5.2.30", "@fontsource-variable/noto-sans-mono": "^5.2.10", - "@lezer/common": "^1.4.0", + "@lezer/common": "^1.5.0", "@lezer/generator": "^1.8.0", "@lezer/highlight": "^1.2.3", - "@lezer/lr": "^1.4.5", + "@lezer/lr": "^1.4.7", "@material/material-color-utilities": "^0.3.0", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@modyfi/vite-plugin-yaml": "^1.1.1", "@sveltejs/adapter-static": "^3.0.10", - "@sveltejs/kit": "^2.49.2", - "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@sveltejs/kit": "^2.49.3", + "@sveltejs/vite-plugin-svelte": "^6.2.3", "@tauri-apps/api": "^1.6.0", "@tauri-apps/cli": "^1.6.0", "@types/dom-view-transitions": "^1.0.6", @@ -76,29 +78,29 @@ "matrix-js-sdk": "^37.12.0", "npm-run-all": "^4.1.5", "prettier": "^3.7.4", - "prettier-plugin-css-order": "^2.1.2", + "prettier-plugin-css-order": "^2.2.0", "prettier-plugin-svelte": "^3.4.1", "rxjs": "^7.8.2", - "sass": "^1.97.0", + "sass": "^1.97.2", "semver": "^7.7.3", - "socket.io-client": "^4.8.1", + "socket.io-client": "^4.8.3", "stylelint": "^16.26.1", "stylelint-config-html": "^1.1.0", "stylelint-config-prettier-scss": "^1.0.0", "stylelint-config-recommended-scss": "^16.0.2", "stylelint-config-standard-scss": "^16.0.0", - "svelte": "5.37.1", - "svelte-check": "^4.3.4", + "svelte": "5.46.1", + "svelte-check": "^4.3.5", "svelte-preprocess": "^6.0.3", "tippy.js": "^6.3.7", "typesafe-i18n": "^5.26.2", - "typescript": "^5.8.3", - "vite": "^7.0.6", + "typescript": "^5.9.3", + "vite": "^7.3.1", "vite-plugin-mkcert": "^1.17.9", - "vite-plugin-pwa": "^1.0.2", + "vite-plugin-pwa": "^1.2.0", "vitest": "^4.0.16", "web-serial-polyfill": "^1.0.15", - "workbox-window": "^7.3.0" + "workbox-window": "^7.4.0" }, "type": "module" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b2cdb3c..f58e936b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@codemirror/autocomplete': specifier: ^6.20.0 version: 6.20.0 + '@codemirror/collab': + specifier: ^6.1.1 + version: 6.1.1 '@codemirror/commands': specifier: ^6.10.1 version: 6.10.1 @@ -18,17 +21,20 @@ importers: specifier: ^6.2.4 version: 6.2.4 '@codemirror/language': - specifier: ^6.11.3 - version: 6.11.3 + specifier: ^6.12.1 + version: 6.12.1 + '@codemirror/lint': + specifier: ^6.9.2 + version: 6.9.2 '@codemirror/merge': specifier: ^6.11.2 version: 6.11.2 '@codemirror/state': - specifier: ^6.5.2 - version: 6.5.2 + specifier: ^6.5.3 + version: 6.5.3 '@codemirror/view': - specifier: ^6.39.4 - version: 6.39.4 + specifier: ^6.39.9 + version: 6.39.9 '@fontsource-variable/material-symbols-rounded': specifier: ^5.2.30 version: 5.2.30 @@ -36,8 +42,8 @@ importers: specifier: ^5.2.10 version: 5.2.10 '@lezer/common': - specifier: ^1.4.0 - version: 1.4.0 + specifier: ^1.5.0 + version: 1.5.0 '@lezer/generator': specifier: ^1.8.0 version: 1.8.0 @@ -45,29 +51,29 @@ importers: specifier: ^1.2.3 version: 1.2.3 '@lezer/lr': - specifier: ^1.4.5 - version: 1.4.5 + specifier: ^1.4.7 + version: 1.4.7 '@material/material-color-utilities': specifier: ^0.3.0 version: 0.3.0 '@melt-ui/pp': specifier: ^0.3.2 - version: 0.3.2(@melt-ui/svelte@0.86.6(svelte@5.37.1))(svelte@5.37.1) + version: 0.3.2(@melt-ui/svelte@0.86.6(svelte@5.46.1))(svelte@5.46.1) '@melt-ui/svelte': specifier: ^0.86.6 - version: 0.86.6(svelte@5.37.1) + version: 0.86.6(svelte@5.46.1) '@modyfi/vite-plugin-yaml': specifier: ^1.1.1 - version: 1.1.1(rollup@2.79.2)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + version: 1.1.1(rollup@2.79.2)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) '@sveltejs/adapter-static': specifier: ^3.0.10 - version: 3.0.10(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1))) + version: 3.0.10(@sveltejs/kit@2.49.3(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(typescript@5.9.3)(vite@7.3.1(sass@1.97.2)(terser@5.44.1))) '@sveltejs/kit': - specifier: ^2.49.2 - version: 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + specifier: ^2.49.3 + version: 2.49.3(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(typescript@5.9.3)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) '@sveltejs/vite-plugin-svelte': - specifier: ^6.2.1 - version: 6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + specifier: ^6.2.3 + version: 6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) '@tauri-apps/api': specifier: ^1.6.0 version: 1.6.0 @@ -94,7 +100,7 @@ importers: version: 2023.10.7 '@vite-pwa/sveltekit': specifier: ^1.1.0 - version: 1.1.0(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(vite@7.0.6(sass@1.97.0)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.3.0) + version: 1.1.0(@sveltejs/kit@2.49.3(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(typescript@5.9.3)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(vite@7.3.1(sass@1.97.2)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.4.0) autoprefixer: specifier: ^10.4.23 version: 10.4.23(postcss@8.5.6) @@ -135,81 +141,77 @@ importers: specifier: ^3.7.4 version: 3.7.4 prettier-plugin-css-order: - specifier: ^2.1.2 - version: 2.1.2(postcss@8.5.6)(prettier@3.7.4) + specifier: ^2.2.0 + version: 2.2.0(postcss@8.5.6)(prettier@3.7.4) prettier-plugin-svelte: specifier: ^3.4.1 - version: 3.4.1(prettier@3.7.4)(svelte@5.37.1) + version: 3.4.1(prettier@3.7.4)(svelte@5.46.1) rxjs: specifier: ^7.8.2 version: 7.8.2 sass: - specifier: ^1.97.0 - version: 1.97.0 + specifier: ^1.97.2 + version: 1.97.2 semver: specifier: ^7.7.3 version: 7.7.3 socket.io-client: - specifier: ^4.8.1 - version: 4.8.1 + specifier: ^4.8.3 + version: 4.8.3 stylelint: specifier: ^16.26.1 - version: 16.26.1(typescript@5.8.3) + version: 16.26.1(typescript@5.9.3) stylelint-config-html: specifier: ^1.1.0 - version: 1.1.0(postcss-html@1.7.0)(stylelint@16.26.1(typescript@5.8.3)) + version: 1.1.0(postcss-html@1.7.0)(stylelint@16.26.1(typescript@5.9.3)) stylelint-config-prettier-scss: specifier: ^1.0.0 - version: 1.0.0(stylelint@16.26.1(typescript@5.8.3)) + version: 1.0.0(stylelint@16.26.1(typescript@5.9.3)) stylelint-config-recommended-scss: specifier: ^16.0.2 - version: 16.0.2(postcss@8.5.6)(stylelint@16.26.1(typescript@5.8.3)) + version: 16.0.2(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)) stylelint-config-standard-scss: specifier: ^16.0.0 - version: 16.0.0(postcss@8.5.6)(stylelint@16.26.1(typescript@5.8.3)) + version: 16.0.0(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)) svelte: - specifier: 5.37.1 - version: 5.37.1 + specifier: 5.46.1 + version: 5.46.1 svelte-check: - specifier: ^4.3.4 - version: 4.3.4(picomatch@4.0.3)(svelte@5.37.1)(typescript@5.8.3) + specifier: ^4.3.5 + version: 4.3.5(picomatch@4.0.3)(svelte@5.46.1)(typescript@5.9.3) svelte-preprocess: specifier: ^6.0.3 - version: 6.0.3(@babel/core@7.28.5)(postcss@8.5.6)(sass@1.97.0)(svelte@5.37.1)(typescript@5.8.3) + version: 6.0.3(@babel/core@7.28.5)(postcss@8.5.6)(sass@1.97.2)(svelte@5.46.1)(typescript@5.9.3) tippy.js: specifier: ^6.3.7 version: 6.3.7 typesafe-i18n: specifier: ^5.26.2 - version: 5.26.2(typescript@5.8.3) + version: 5.26.2(typescript@5.9.3) typescript: - specifier: ^5.8.3 - version: 5.8.3 + specifier: ^5.9.3 + version: 5.9.3 vite: - specifier: ^7.0.6 - version: 7.0.6(sass@1.97.0)(terser@5.44.1) + specifier: ^7.3.1 + version: 7.3.1(sass@1.97.2)(terser@5.44.1) vite-plugin-mkcert: specifier: ^1.17.9 - version: 1.17.9(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + version: 1.17.9(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) vite-plugin-pwa: - specifier: ^1.0.2 - version: 1.0.2(vite@7.0.6(sass@1.97.0)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.3.0) + specifier: ^1.2.0 + version: 1.2.0(vite@7.3.1(sass@1.97.2)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.4.0) vitest: specifier: ^4.0.16 - version: 4.0.16(jsdom@26.1.0)(sass@1.97.0)(terser@5.44.1) + version: 4.0.16(jsdom@26.1.0)(sass@1.97.2)(terser@5.44.1) web-serial-polyfill: specifier: ^1.0.15 version: 1.0.15 workbox-window: - specifier: ^7.3.0 - version: 7.3.0 + specifier: ^7.4.0 + version: 7.4.0 packages: - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - '@apideck/better-ajv-errors@0.3.6': resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} engines: {node: '>=10'} @@ -739,17 +741,20 @@ packages: '@codemirror/autocomplete@6.20.0': resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} + '@codemirror/collab@6.1.1': + resolution: {integrity: sha512-tkIn9Jguh98ie12dbBuba3lE8LHUkaMrIFuCVeVGhncSczFdKmX25vC12+58+yqQW5AXi3py6jWY0W+jelyglA==} + '@codemirror/commands@6.10.1': resolution: {integrity: sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q==} '@codemirror/lang-javascript@6.2.4': resolution: {integrity: sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==} - '@codemirror/language@6.11.3': - resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==} + '@codemirror/language@6.12.1': + resolution: {integrity: sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==} - '@codemirror/lint@6.8.1': - resolution: {integrity: sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==} + '@codemirror/lint@6.9.2': + resolution: {integrity: sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==} '@codemirror/merge@6.11.2': resolution: {integrity: sha512-NO5EJd2rLRbwVWLgMdhIntDIhfDtMOKYEZgqV5WnkNUS2oXOCVWLPjG/kgl/Jth2fGiOuG947bteqxP9nBXmMg==} @@ -757,11 +762,11 @@ packages: '@codemirror/search@6.5.6': resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} - '@codemirror/state@6.5.2': - resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} + '@codemirror/state@6.5.3': + resolution: {integrity: sha512-MerMzJzlXogk2fxWFU1nKp36bY5orBG59HnPiz0G9nLRebWa0zXuv2siH6PLIHBvv5TH8CkQRqjBs0MlxCZu+A==} - '@codemirror/view@6.39.4': - resolution: {integrity: sha512-xMF6OfEAUVY5Waega4juo1QGACfNkNF+aJLqpd8oUJz96ms2zbfQ9Gh35/tI3y8akEV31FruKfj7hBnIU/nkqA==} + '@codemirror/view@6.39.9': + resolution: {integrity: sha512-miGSIfBOKC1s2oHoa80dp+BjtsL8sXsrgGlQnQuOcfvaedcQUtqddTmKbJSDkLl4mkgPvZyXuKic2HDNYcJLYA==} '@csstools/color-helpers@5.0.2': resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} @@ -828,152 +833,158 @@ packages: '@dual-bundle/import-meta-resolve@4.2.1': resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} - '@esbuild/aix-ppc64@0.25.2': - resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==} + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.2': - resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.2': - resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.2': - resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.2': - resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.2': - resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.2': - resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.2': - resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.2': - resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.2': - resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.2': - resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.2': - resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.2': - resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.2': - resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.2': - resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.2': - resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.2': - resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.2': - resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.2': - resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.2': - resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.2': - resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.25.2': - resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.2': - resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.2': - resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.2': - resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1011,10 +1022,6 @@ packages: '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - '@jridgewell/gen-mapping@0.3.5': - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} - '@jridgewell/remapping@2.3.5': resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} @@ -1022,25 +1029,15 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.11': resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} @@ -1053,8 +1050,8 @@ packages: '@keyv/serialize@1.1.1': resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} - '@lezer/common@1.4.0': - resolution: {integrity: sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==} + '@lezer/common@1.5.0': + resolution: {integrity: sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==} '@lezer/generator@1.8.0': resolution: {integrity: sha512-/SF4EDWowPqV1jOgoGSGTIFsE7Ezdr7ZYxyihl5eMKVO5tlnpIhFcDavgm1hHY5GEonoOAEnJ0CU0x+tvuAuUg==} @@ -1066,8 +1063,8 @@ packages: '@lezer/javascript@1.4.17': resolution: {integrity: sha512-bYW4ctpyGK+JMumDApeUzuIezX01H76R1foD6LcRX224FWfyYit/HYxiPGDjXXe/wQWASjCvVGoukTH68+0HIA==} - '@lezer/lr@1.4.5': - resolution: {integrity: sha512-/YTRKP5yPPSo1xImYQk7AZZMAgap0kegzqCSYHjAL9x1AZ0ZQW+IpcEzMKagCsbTsLnVeWkxYrCNeXG8xEPrjg==} + '@lezer/lr@1.4.7': + resolution: {integrity: sha512-wNIFWdSUfX9Jc6ePMzxSPVgTVB4EOfDIwLQLWASyiUdHKaMsiilj9bYiGkGQCKVodd0x6bgQCV207PILGFCF9Q==} '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} @@ -1372,18 +1369,21 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/kit@2.49.2': - resolution: {integrity: sha512-Vp3zX/qlwerQmHMP6x0Ry1oY7eKKRcOWGc2P59srOp4zcqyn+etJyQpELgOi4+ZSUgteX8Y387NuwruLgGXLUQ==} + '@sveltejs/kit@2.49.3': + resolution: {integrity: sha512-luTmE2Isk9GRJnitqanLoByKBiyLdfLpV2qV9a25JMxjbQt919TVqG8pibJDkxTvX9+w2k/9IL7o+/RtG++3QA==} engines: {node: '>=18.13'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.0.0 '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: ^5.3.3 vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 peerDependenciesMeta: '@opentelemetry/api': optional: true + typescript: + optional: true '@sveltejs/vite-plugin-svelte-inspector@5.0.0': resolution: {integrity: sha512-iwQ8Z4ET6ZFSt/gC+tVfcsSBHwsqc6RumSaiLUkAurW3BCpJam65cmHw0oOlDMTO0u+PZi9hilBRYN+LZNHTUQ==} @@ -1393,8 +1393,8 @@ packages: svelte: ^5.0.0 vite: ^6.3.0 || ^7.0.0 - '@sveltejs/vite-plugin-svelte@6.2.1': - resolution: {integrity: sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ==} + '@sveltejs/vite-plugin-svelte@6.2.3': + resolution: {integrity: sha512-a+uxqQ9j6Lxmq4plbGaNdM9hgDCZyxAv/yvuyF5iWoA2H5icZkqD3rdK155ZQgFLX2lc3NvahHG4OgKpYqYPiQ==} engines: {node: ^20.19 || ^22.12 || >=24} peerDependencies: svelte: ^5.0.0 @@ -1493,9 +1493,6 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} - '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -1577,11 +1574,6 @@ packages: '@vitest/utils@4.0.16': resolution: {integrity: sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA==} - acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -1961,8 +1953,8 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} - css-declaration-sorter@7.2.0: - resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} + css-declaration-sorter@7.3.1: + resolution: {integrity: sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.0.9 @@ -2345,8 +2337,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild@0.25.2: - resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==} + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} hasBin: true @@ -2364,8 +2356,8 @@ packages: esptool-js@0.5.7: resolution: {integrity: sha512-k3pkXU9OTySCd58OUDjuJWNnFjM+QpPWAghxyWPm3zNfaLiP4ex2jNd7Rj0jWPu3/fgvwau236tetsTZrh4x5g==} - esrap@2.1.0: - resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==} + esrap@2.2.1: + resolution: {integrity: sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==} estree-walker@1.0.1: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} @@ -2434,14 +2426,6 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - fdir@6.4.2: - resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fdir@6.4.6: resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} peerDependencies: @@ -3144,9 +3128,6 @@ packages: magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -3390,10 +3371,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -3464,8 +3441,8 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - prettier-plugin-css-order@2.1.2: - resolution: {integrity: sha512-vomxPjHI6pOMYcBuouSJHxxQClJXaUpU9rsV9IAO2wrSTZILRRlrxAAR8t9UF6wtczLkLfNRFUwM+ZbGXOONUA==} + prettier-plugin-css-order@2.2.0: + resolution: {integrity: sha512-GCkwEgQ2roT7le+zpUFQThPDO4x5EXcZmY9Rj6rvO++I/nATTGBWdZdsooha/BlvIBbZclJzXsgJdlKWrys9+w==} engines: {node: '>=16'} peerDependencies: prettier: 3.x @@ -3658,8 +3635,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.97.0: - resolution: {integrity: sha512-KR0igP1z4avUJetEuIeOdDlwaUDvkH8wSx7FdSjyYBS3dpyX3TzHfAMO0G1Q4/3cdjcmi3r7idh+KCmKqS+KeQ==} + sass@1.97.2: + resolution: {integrity: sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==} engines: {node: '>=14.0.0'} hasBin: true @@ -3770,8 +3747,8 @@ packages: smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} - socket.io-client@4.8.1: - resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==} + socket.io-client@4.8.3: + resolution: {integrity: sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==} engines: {node: '>=10.0.0'} socket.io-parser@4.2.4: @@ -3964,8 +3941,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svelte-check@4.3.4: - resolution: {integrity: sha512-DVWvxhBrDsd+0hHWKfjP99lsSXASeOhHJYyuKOFYJcP7ThfSCKgjVarE8XfuMWpS5JV3AlDf+iK1YGGo2TACdw==} + svelte-check@4.3.5: + resolution: {integrity: sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q==} engines: {node: '>= 18.0.0'} hasBin: true peerDependencies: @@ -4009,8 +3986,8 @@ packages: typescript: optional: true - svelte@5.37.1: - resolution: {integrity: sha512-h8arWpQZ+3z8eahyBT5KkiBOUsG6xvI5Ykg0ozRr9xEdImgSMUPUlOFWRNkUsT7Ti0DSUCTEbPoped0aoxFyWA==} + svelte@5.46.1: + resolution: {integrity: sha512-ynjfCHD3nP2el70kN5Pmg37sSi0EjOm9FgHYQdC4giWG/hzO3AatzXXJJgP305uIhGQxSufJLuYWtkY8uK/8RA==} engines: {node: '>=18'} svg-tags@1.0.0: @@ -4055,10 +4032,6 @@ packages: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} - tinyglobby@0.2.10: - resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -4175,8 +4148,8 @@ packages: peerDependencies: typescript: '>=3.5.1' - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true @@ -4264,18 +4237,6 @@ packages: peerDependencies: vite: '>=3' - vite-plugin-pwa@1.0.2: - resolution: {integrity: sha512-O3UwjsCnoDclgJANoOgzzqW7SFgwXE/th2OmUP/ILxHKwzWxxKDBu+B/Xa9Cv4IgSVSnj2HgRVIJ7F15+vQFkA==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@vite-pwa/assets-generator': ^1.0.0 - vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - workbox-build: ^7.3.0 - workbox-window: ^7.3.0 - peerDependenciesMeta: - '@vite-pwa/assets-generator': - optional: true - vite-plugin-pwa@1.2.0: resolution: {integrity: sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==} engines: {node: '>=16.0.0'} @@ -4288,8 +4249,8 @@ packages: '@vite-pwa/assets-generator': optional: true - vite@7.0.6: - resolution: {integrity: sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4455,8 +4416,8 @@ packages: workbox-core@7.1.0: resolution: {integrity: sha512-5KB4KOY8rtL31nEF7BfvU7FMzKT4B5TkbYa2tzkS+Peqj0gayMT9SytSFtNzlrvMaWgv6y/yvP9C0IbpFjV30Q==} - workbox-core@7.3.0: - resolution: {integrity: sha512-Z+mYrErfh4t3zi7NVTvOuACB0A/jA3bgxUN3PwtAVHvfEsZxV9Iju580VEETug3zYJRc0Dmii/aixI/Uxj8fmw==} + workbox-core@7.4.0: + resolution: {integrity: sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==} workbox-expiration@7.1.0: resolution: {integrity: sha512-m5DcMY+A63rJlPTbbBNtpJ20i3enkyOtSgYfv/l8h+D6YbbNiA0zKEkCUaMsdDlxggla1oOfRkyqTvl5Ni5KQQ==} @@ -4491,8 +4452,8 @@ packages: workbox-window@7.1.0: resolution: {integrity: sha512-ZHeROyqR+AS5UPzholQRDttLFqGMwP0Np8MKWAdyxsDETxq3qOAyXvqessc3GniohG6e0mAqSQyKOHmT8zPF7g==} - workbox-window@7.3.0: - resolution: {integrity: sha512-qW8PDy16OV1UBaUNGlTVcepzrlzyzNW/ZJvFQQs2j2TzGsg6IKjcpZC1RSquqQnTOafl5pCj5bGfAHlCjOOjdA==} + workbox-window@7.4.0: + resolution: {integrity: sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw==} wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} @@ -4559,11 +4520,6 @@ packages: snapshots: - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - '@apideck/better-ajv-errors@0.3.6(ajv@8.17.1)': dependencies: ajv: 8.17.1 @@ -5265,64 +5221,68 @@ snapshots: '@codemirror/autocomplete@6.20.0': dependencies: - '@codemirror/language': 6.11.3 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.39.4 - '@lezer/common': 1.4.0 + '@codemirror/language': 6.12.1 + '@codemirror/state': 6.5.3 + '@codemirror/view': 6.39.9 + '@lezer/common': 1.5.0 + + '@codemirror/collab@6.1.1': + dependencies: + '@codemirror/state': 6.5.3 '@codemirror/commands@6.10.1': dependencies: - '@codemirror/language': 6.11.3 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.39.4 - '@lezer/common': 1.4.0 + '@codemirror/language': 6.12.1 + '@codemirror/state': 6.5.3 + '@codemirror/view': 6.39.9 + '@lezer/common': 1.5.0 '@codemirror/lang-javascript@6.2.4': dependencies: '@codemirror/autocomplete': 6.20.0 - '@codemirror/language': 6.11.3 - '@codemirror/lint': 6.8.1 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.39.4 - '@lezer/common': 1.4.0 + '@codemirror/language': 6.12.1 + '@codemirror/lint': 6.9.2 + '@codemirror/state': 6.5.3 + '@codemirror/view': 6.39.9 + '@lezer/common': 1.5.0 '@lezer/javascript': 1.4.17 - '@codemirror/language@6.11.3': + '@codemirror/language@6.12.1': dependencies: - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.39.4 - '@lezer/common': 1.4.0 + '@codemirror/state': 6.5.3 + '@codemirror/view': 6.39.9 + '@lezer/common': 1.5.0 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.5 + '@lezer/lr': 1.4.7 style-mod: 4.1.2 - '@codemirror/lint@6.8.1': + '@codemirror/lint@6.9.2': dependencies: - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.39.4 + '@codemirror/state': 6.5.3 + '@codemirror/view': 6.39.9 crelt: 1.0.6 '@codemirror/merge@6.11.2': dependencies: - '@codemirror/language': 6.11.3 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.39.4 + '@codemirror/language': 6.12.1 + '@codemirror/state': 6.5.3 + '@codemirror/view': 6.39.9 '@lezer/highlight': 1.2.3 style-mod: 4.1.2 '@codemirror/search@6.5.6': dependencies: - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.39.4 + '@codemirror/state': 6.5.3 + '@codemirror/view': 6.39.9 crelt: 1.0.6 - '@codemirror/state@6.5.2': + '@codemirror/state@6.5.3': dependencies: '@marijn/find-cluster-break': 1.0.2 - '@codemirror/view@6.39.4': + '@codemirror/view@6.39.9': dependencies: - '@codemirror/state': 6.5.2 + '@codemirror/state': 6.5.3 crelt: 1.0.6 style-mod: 4.1.2 w3c-keyname: 2.2.8 @@ -5394,79 +5354,82 @@ snapshots: '@dual-bundle/import-meta-resolve@4.2.1': {} - '@esbuild/aix-ppc64@0.25.2': + '@esbuild/aix-ppc64@0.27.2': + optional: true + + '@esbuild/android-arm64@0.27.2': optional: true - '@esbuild/android-arm64@0.25.2': + '@esbuild/android-arm@0.27.2': optional: true - '@esbuild/android-arm@0.25.2': + '@esbuild/android-x64@0.27.2': optional: true - '@esbuild/android-x64@0.25.2': + '@esbuild/darwin-arm64@0.27.2': optional: true - '@esbuild/darwin-arm64@0.25.2': + '@esbuild/darwin-x64@0.27.2': optional: true - '@esbuild/darwin-x64@0.25.2': + '@esbuild/freebsd-arm64@0.27.2': optional: true - '@esbuild/freebsd-arm64@0.25.2': + '@esbuild/freebsd-x64@0.27.2': optional: true - '@esbuild/freebsd-x64@0.25.2': + '@esbuild/linux-arm64@0.27.2': optional: true - '@esbuild/linux-arm64@0.25.2': + '@esbuild/linux-arm@0.27.2': optional: true - '@esbuild/linux-arm@0.25.2': + '@esbuild/linux-ia32@0.27.2': optional: true - '@esbuild/linux-ia32@0.25.2': + '@esbuild/linux-loong64@0.27.2': optional: true - '@esbuild/linux-loong64@0.25.2': + '@esbuild/linux-mips64el@0.27.2': optional: true - '@esbuild/linux-mips64el@0.25.2': + '@esbuild/linux-ppc64@0.27.2': optional: true - '@esbuild/linux-ppc64@0.25.2': + '@esbuild/linux-riscv64@0.27.2': optional: true - '@esbuild/linux-riscv64@0.25.2': + '@esbuild/linux-s390x@0.27.2': optional: true - '@esbuild/linux-s390x@0.25.2': + '@esbuild/linux-x64@0.27.2': optional: true - '@esbuild/linux-x64@0.25.2': + '@esbuild/netbsd-arm64@0.27.2': optional: true - '@esbuild/netbsd-arm64@0.25.2': + '@esbuild/netbsd-x64@0.27.2': optional: true - '@esbuild/netbsd-x64@0.25.2': + '@esbuild/openbsd-arm64@0.27.2': optional: true - '@esbuild/openbsd-arm64@0.25.2': + '@esbuild/openbsd-x64@0.27.2': optional: true - '@esbuild/openbsd-x64@0.25.2': + '@esbuild/openharmony-arm64@0.27.2': optional: true - '@esbuild/sunos-x64@0.25.2': + '@esbuild/sunos-x64@0.27.2': optional: true - '@esbuild/win32-arm64@0.25.2': + '@esbuild/win32-arm64@0.27.2': optional: true - '@esbuild/win32-ia32@0.25.2': + '@esbuild/win32-ia32@0.27.2': optional: true - '@esbuild/win32-x64@0.25.2': + '@esbuild/win32-x64@0.27.2': optional: true '@floating-ui/core@1.6.7': @@ -5508,12 +5471,6 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/gen-mapping@0.3.5': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 - '@jridgewell/remapping@2.3.5': dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -5521,8 +5478,6 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.11': dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -5530,15 +5485,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.4.15': {} - '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -5552,26 +5500,26 @@ snapshots: '@keyv/serialize@1.1.1': {} - '@lezer/common@1.4.0': {} + '@lezer/common@1.5.0': {} '@lezer/generator@1.8.0': dependencies: - '@lezer/common': 1.4.0 - '@lezer/lr': 1.4.5 + '@lezer/common': 1.5.0 + '@lezer/lr': 1.4.7 '@lezer/highlight@1.2.3': dependencies: - '@lezer/common': 1.4.0 + '@lezer/common': 1.5.0 '@lezer/javascript@1.4.17': dependencies: - '@lezer/common': 1.4.0 + '@lezer/common': 1.5.0 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.5 + '@lezer/lr': 1.4.7 - '@lezer/lr@1.4.5': + '@lezer/lr@1.4.7': dependencies: - '@lezer/common': 1.4.0 + '@lezer/common': 1.5.0 '@marijn/find-cluster-break@1.0.2': {} @@ -5579,14 +5527,14 @@ snapshots: '@matrix-org/matrix-sdk-crypto-wasm@15.1.0': {} - '@melt-ui/pp@0.3.2(@melt-ui/svelte@0.86.6(svelte@5.37.1))(svelte@5.37.1)': + '@melt-ui/pp@0.3.2(@melt-ui/svelte@0.86.6(svelte@5.46.1))(svelte@5.46.1)': dependencies: - '@melt-ui/svelte': 0.86.6(svelte@5.37.1) + '@melt-ui/svelte': 0.86.6(svelte@5.46.1) estree-walker: 3.0.3 magic-string: 0.30.10 - svelte: 5.37.1 + svelte: 5.46.1 - '@melt-ui/svelte@0.86.6(svelte@5.37.1)': + '@melt-ui/svelte@0.86.6(svelte@5.46.1)': dependencies: '@floating-ui/core': 1.6.7 '@floating-ui/dom': 1.6.10 @@ -5594,14 +5542,14 @@ snapshots: dequal: 2.0.3 focus-trap: 7.5.4 nanoid: 5.0.7 - svelte: 5.37.1 + svelte: 5.46.1 - '@modyfi/vite-plugin-yaml@1.1.1(rollup@2.79.2)(vite@7.0.6(sass@1.97.0)(terser@5.44.1))': + '@modyfi/vite-plugin-yaml@1.1.1(rollup@2.79.2)(vite@7.3.1(sass@1.97.2)(terser@5.44.1))': dependencies: '@rollup/pluginutils': 5.1.0(rollup@2.79.2) js-yaml: 4.1.0 tosource: 2.0.0-alpha.3 - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) transitivePeerDependencies: - rollup @@ -5809,55 +5757,53 @@ snapshots: magic-string: 0.25.9 string.prototype.matchall: 4.0.12 - '@sveltejs/acorn-typescript@1.0.5(acorn@8.12.1)': - dependencies: - acorn: 8.12.1 - '@sveltejs/acorn-typescript@1.0.5(acorn@8.15.0)': dependencies: acorn: 8.15.0 - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))': + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.49.3(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(typescript@5.9.3)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))': dependencies: - '@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + '@sveltejs/kit': 2.49.3(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(typescript@5.9.3)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) - '@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1))': + '@sveltejs/kit@2.49.3(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(typescript@5.9.3)(vite@7.3.1(sass@1.97.2)(terser@5.44.1))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + '@sveltejs/vite-plugin-svelte': 6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 0.6.0 devalue: 5.6.1 esm-env: 1.2.2 kleur: 4.1.5 - magic-string: 0.30.17 + magic-string: 0.30.21 mrmime: 2.0.0 sade: 1.8.1 set-cookie-parser: 2.6.0 sirv: 3.0.0 - svelte: 5.37.1 - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) + svelte: 5.46.1 + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) + optionalDependencies: + typescript: 5.9.3 - '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) - debug: 4.4.1(supports-color@8.1.1) - svelte: 5.37.1 - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) + '@sveltejs/vite-plugin-svelte': 6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) + debug: 4.4.3 + svelte: 5.46.1 + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1))': + '@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) - debug: 4.4.1(supports-color@8.1.1) + '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) deepmerge: 4.3.1 - magic-string: 0.30.17 - svelte: 5.37.1 - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) - vitefu: 1.1.1(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + magic-string: 0.30.21 + obug: 2.1.1 + svelte: 5.46.1 + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) + vitefu: 1.1.1(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) transitivePeerDependencies: - supports-color @@ -5928,8 +5874,6 @@ snapshots: '@types/estree@1.0.6': {} - '@types/estree@1.0.7': {} - '@types/estree@1.0.8': {} '@types/events@3.0.3': {} @@ -5964,12 +5908,12 @@ snapshots: '@types/node': 20.14.10 optional: true - '@vite-pwa/sveltekit@1.1.0(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(vite@7.0.6(sass@1.97.0)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.3.0)': + '@vite-pwa/sveltekit@1.1.0(@sveltejs/kit@2.49.3(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(typescript@5.9.3)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(vite@7.3.1(sass@1.97.2)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.4.0)': dependencies: - '@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)))(svelte@5.37.1)(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + '@sveltejs/kit': 2.49.3(@sveltejs/vite-plugin-svelte@6.2.3(svelte@5.46.1)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)))(svelte@5.46.1)(typescript@5.9.3)(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) kolorist: 1.8.0 tinyglobby: 0.2.14 - vite-plugin-pwa: 1.2.0(vite@7.0.6(sass@1.97.0)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.3.0) + vite-plugin-pwa: 1.2.0(vite@7.3.1(sass@1.97.2)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.4.0) transitivePeerDependencies: - supports-color - vite @@ -5985,13 +5929,13 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.16(vite@7.0.6(sass@1.97.0)(terser@5.44.1))': + '@vitest/mocker@4.0.16(vite@7.3.1(sass@1.97.2)(terser@5.44.1))': dependencies: '@vitest/spy': 4.0.16 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) '@vitest/pretty-format@4.0.16': dependencies: @@ -6015,8 +5959,6 @@ snapshots: '@vitest/pretty-format': 4.0.16 tinyrainbow: 3.0.3 - acorn@8.12.1: {} - acorn@8.15.0: {} agent-base@7.1.3: {} @@ -6315,11 +6257,11 @@ snapshots: dependencies: '@codemirror/autocomplete': 6.20.0 '@codemirror/commands': 6.10.1 - '@codemirror/language': 6.11.3 - '@codemirror/lint': 6.8.1 + '@codemirror/language': 6.12.1 + '@codemirror/lint': 6.9.2 '@codemirror/search': 6.5.6 - '@codemirror/state': 6.5.2 - '@codemirror/view': 6.39.4 + '@codemirror/state': 6.5.3 + '@codemirror/view': 6.39.9 color-convert@1.9.3: dependencies: @@ -6366,14 +6308,14 @@ snapshots: core-util-is@1.0.2: {} - cosmiconfig@9.0.0(typescript@5.8.3): + cosmiconfig@9.0.0(typescript@5.9.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.1 parse-json: 5.2.0 optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.3 crelt@1.0.6: {} @@ -6399,7 +6341,7 @@ snapshots: crypto-random-string@2.0.0: {} - css-declaration-sorter@7.2.0(postcss@8.5.6): + css-declaration-sorter@7.3.1(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -6945,33 +6887,34 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild@0.25.2: + esbuild@0.27.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.2 - '@esbuild/android-arm': 0.25.2 - '@esbuild/android-arm64': 0.25.2 - '@esbuild/android-x64': 0.25.2 - '@esbuild/darwin-arm64': 0.25.2 - '@esbuild/darwin-x64': 0.25.2 - '@esbuild/freebsd-arm64': 0.25.2 - '@esbuild/freebsd-x64': 0.25.2 - '@esbuild/linux-arm': 0.25.2 - '@esbuild/linux-arm64': 0.25.2 - '@esbuild/linux-ia32': 0.25.2 - '@esbuild/linux-loong64': 0.25.2 - '@esbuild/linux-mips64el': 0.25.2 - '@esbuild/linux-ppc64': 0.25.2 - '@esbuild/linux-riscv64': 0.25.2 - '@esbuild/linux-s390x': 0.25.2 - '@esbuild/linux-x64': 0.25.2 - '@esbuild/netbsd-arm64': 0.25.2 - '@esbuild/netbsd-x64': 0.25.2 - '@esbuild/openbsd-arm64': 0.25.2 - '@esbuild/openbsd-x64': 0.25.2 - '@esbuild/sunos-x64': 0.25.2 - '@esbuild/win32-arm64': 0.25.2 - '@esbuild/win32-ia32': 0.25.2 - '@esbuild/win32-x64': 0.25.2 + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 escalade@3.2.0: {} @@ -6985,9 +6928,9 @@ snapshots: pako: 2.1.0 tslib: 2.6.3 - esrap@2.1.0: + esrap@2.2.1: dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 estree-walker@1.0.1: {} @@ -7059,10 +7002,6 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.4.2(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fdir@6.4.6(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -7536,7 +7475,7 @@ snapshots: is-reference@3.0.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 is-regex@1.1.4: dependencies: @@ -7780,10 +7719,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 - magic-string@0.30.17: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -8011,8 +7946,6 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.2: {} - picomatch@4.0.3: {} pidtree@0.3.1: {} @@ -8065,19 +7998,19 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - prettier-plugin-css-order@2.1.2(postcss@8.5.6)(prettier@3.7.4): + prettier-plugin-css-order@2.2.0(postcss@8.5.6)(prettier@3.7.4): dependencies: - css-declaration-sorter: 7.2.0(postcss@8.5.6) + css-declaration-sorter: 7.3.1(postcss@8.5.6) postcss-less: 6.0.0(postcss@8.5.6) postcss-scss: 4.0.9(postcss@8.5.6) prettier: 3.7.4 transitivePeerDependencies: - postcss - prettier-plugin-svelte@3.4.1(prettier@3.7.4)(svelte@5.37.1): + prettier-plugin-svelte@3.4.1(prettier@3.7.4)(svelte@5.46.1): dependencies: prettier: 3.7.4 - svelte: 5.37.1 + svelte: 5.46.1 prettier@3.7.4: {} @@ -8289,7 +8222,7 @@ snapshots: safer-buffer@2.1.2: {} - sass@1.97.0: + sass@1.97.2: dependencies: chokidar: 4.0.1 immutable: 5.1.1 @@ -8414,10 +8347,10 @@ snapshots: smob@1.5.0: {} - socket.io-client@4.8.1: + socket.io-client@4.8.3: dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.6 + debug: 4.4.3 engine.io-client: 6.6.2 socket.io-parser: 4.2.4 transitivePeerDependencies: @@ -8575,42 +8508,42 @@ snapshots: style-mod@4.1.2: {} - stylelint-config-html@1.1.0(postcss-html@1.7.0)(stylelint@16.26.1(typescript@5.8.3)): + stylelint-config-html@1.1.0(postcss-html@1.7.0)(stylelint@16.26.1(typescript@5.9.3)): dependencies: postcss-html: 1.7.0 - stylelint: 16.26.1(typescript@5.8.3) + stylelint: 16.26.1(typescript@5.9.3) - stylelint-config-prettier-scss@1.0.0(stylelint@16.26.1(typescript@5.8.3)): + stylelint-config-prettier-scss@1.0.0(stylelint@16.26.1(typescript@5.9.3)): dependencies: - stylelint: 16.26.1(typescript@5.8.3) + stylelint: 16.26.1(typescript@5.9.3) - stylelint-config-recommended-scss@16.0.2(postcss@8.5.6)(stylelint@16.26.1(typescript@5.8.3)): + stylelint-config-recommended-scss@16.0.2(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)): dependencies: postcss-scss: 4.0.9(postcss@8.5.6) - stylelint: 16.26.1(typescript@5.8.3) - stylelint-config-recommended: 17.0.0(stylelint@16.26.1(typescript@5.8.3)) - stylelint-scss: 6.12.1(stylelint@16.26.1(typescript@5.8.3)) + stylelint: 16.26.1(typescript@5.9.3) + stylelint-config-recommended: 17.0.0(stylelint@16.26.1(typescript@5.9.3)) + stylelint-scss: 6.12.1(stylelint@16.26.1(typescript@5.9.3)) optionalDependencies: postcss: 8.5.6 - stylelint-config-recommended@17.0.0(stylelint@16.26.1(typescript@5.8.3)): + stylelint-config-recommended@17.0.0(stylelint@16.26.1(typescript@5.9.3)): dependencies: - stylelint: 16.26.1(typescript@5.8.3) + stylelint: 16.26.1(typescript@5.9.3) - stylelint-config-standard-scss@16.0.0(postcss@8.5.6)(stylelint@16.26.1(typescript@5.8.3)): + stylelint-config-standard-scss@16.0.0(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)): dependencies: - stylelint: 16.26.1(typescript@5.8.3) - stylelint-config-recommended-scss: 16.0.2(postcss@8.5.6)(stylelint@16.26.1(typescript@5.8.3)) - stylelint-config-standard: 39.0.1(stylelint@16.26.1(typescript@5.8.3)) + stylelint: 16.26.1(typescript@5.9.3) + stylelint-config-recommended-scss: 16.0.2(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)) + stylelint-config-standard: 39.0.1(stylelint@16.26.1(typescript@5.9.3)) optionalDependencies: postcss: 8.5.6 - stylelint-config-standard@39.0.1(stylelint@16.26.1(typescript@5.8.3)): + stylelint-config-standard@39.0.1(stylelint@16.26.1(typescript@5.9.3)): dependencies: - stylelint: 16.26.1(typescript@5.8.3) - stylelint-config-recommended: 17.0.0(stylelint@16.26.1(typescript@5.8.3)) + stylelint: 16.26.1(typescript@5.9.3) + stylelint-config-recommended: 17.0.0(stylelint@16.26.1(typescript@5.9.3)) - stylelint-scss@6.12.1(stylelint@16.26.1(typescript@5.8.3)): + stylelint-scss@6.12.1(stylelint@16.26.1(typescript@5.9.3)): dependencies: css-tree: 3.1.0 is-plain-object: 5.0.0 @@ -8620,9 +8553,9 @@ snapshots: postcss-resolve-nested-selector: 0.1.6 postcss-selector-parser: 7.1.0 postcss-value-parser: 4.2.0 - stylelint: 16.26.1(typescript@5.8.3) + stylelint: 16.26.1(typescript@5.9.3) - stylelint@16.26.1(typescript@5.8.3): + stylelint@16.26.1(typescript@5.9.3): dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-syntax-patches-for-csstree': 1.0.21 @@ -8632,7 +8565,7 @@ snapshots: '@dual-bundle/import-meta-resolve': 4.2.1 balanced-match: 2.0.0 colord: 2.9.3 - cosmiconfig: 9.0.0(typescript@5.8.3) + cosmiconfig: 9.0.0(typescript@5.9.3) css-functions-list: 3.2.3 css-tree: 3.1.0 debug: 4.4.3 @@ -8686,42 +8619,43 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@4.3.4(picomatch@4.0.3)(svelte@5.37.1)(typescript@5.8.3): + svelte-check@4.3.5(picomatch@4.0.3)(svelte@5.46.1)(typescript@5.9.3): dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 chokidar: 4.0.1 - fdir: 6.4.6(picomatch@4.0.3) + fdir: 6.5.0(picomatch@4.0.3) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.37.1 - typescript: 5.8.3 + svelte: 5.46.1 + typescript: 5.9.3 transitivePeerDependencies: - picomatch - svelte-preprocess@6.0.3(@babel/core@7.28.5)(postcss@8.5.6)(sass@1.97.0)(svelte@5.37.1)(typescript@5.8.3): + svelte-preprocess@6.0.3(@babel/core@7.28.5)(postcss@8.5.6)(sass@1.97.2)(svelte@5.46.1)(typescript@5.9.3): dependencies: - svelte: 5.37.1 + svelte: 5.46.1 optionalDependencies: '@babel/core': 7.28.5 postcss: 8.5.6 - sass: 1.97.0 - typescript: 5.8.3 + sass: 1.97.2 + typescript: 5.9.3 - svelte@5.37.1: + svelte@5.46.1: dependencies: - '@ampproject/remapping': 2.3.0 - '@jridgewell/sourcemap-codec': 1.5.0 - '@sveltejs/acorn-typescript': 1.0.5(acorn@8.12.1) - '@types/estree': 1.0.7 - acorn: 8.12.1 + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) + '@types/estree': 1.0.8 + acorn: 8.15.0 aria-query: 5.3.2 axobject-query: 4.1.0 clsx: 2.1.1 + devalue: 5.6.1 esm-env: 1.2.2 - esrap: 2.1.0 + esrap: 2.2.1 is-reference: 3.0.3 locate-character: 3.0.0 - magic-string: 0.30.17 + magic-string: 0.30.21 zimmerframe: 1.1.2 svg-tags@1.0.0: {} @@ -8764,11 +8698,6 @@ snapshots: tinyexec@1.0.2: {} - tinyglobby@0.2.10: - dependencies: - fdir: 6.4.2(picomatch@4.0.2) - picomatch: 4.0.2 - tinyglobby@0.2.14: dependencies: fdir: 6.4.6(picomatch@4.0.3) @@ -8898,11 +8827,11 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typesafe-i18n@5.26.2(typescript@5.8.3): + typesafe-i18n@5.26.2(typescript@5.9.3): dependencies: - typescript: 5.8.3 + typescript: 5.9.3 - typescript@5.8.3: {} + typescript@5.9.3: {} unbox-primitive@1.0.2: dependencies: @@ -8981,58 +8910,47 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 - vite-plugin-mkcert@1.17.9(vite@7.0.6(sass@1.97.0)(terser@5.44.1)): + vite-plugin-mkcert@1.17.9(vite@7.3.1(sass@1.97.2)(terser@5.44.1)): dependencies: axios: 1.13.2(debug@4.4.3) debug: 4.4.3 picocolors: 1.1.1 - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) - transitivePeerDependencies: - - supports-color - - vite-plugin-pwa@1.0.2(vite@7.0.6(sass@1.97.0)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.3.0): - dependencies: - debug: 4.4.0(supports-color@8.1.1) - pretty-bytes: 6.1.1 - tinyglobby: 0.2.10 - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) - workbox-build: 7.1.1 - workbox-window: 7.3.0 + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) transitivePeerDependencies: - supports-color - vite-plugin-pwa@1.2.0(vite@7.0.6(sass@1.97.0)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.3.0): + vite-plugin-pwa@1.2.0(vite@7.3.1(sass@1.97.2)(terser@5.44.1))(workbox-build@7.1.1)(workbox-window@7.4.0): dependencies: - debug: 4.4.1(supports-color@8.1.1) + debug: 4.4.3 pretty-bytes: 6.1.1 - tinyglobby: 0.2.14 - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) + tinyglobby: 0.2.15 + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) workbox-build: 7.1.1 - workbox-window: 7.3.0 + workbox-window: 7.4.0 transitivePeerDependencies: - supports-color - vite@7.0.6(sass@1.97.0)(terser@5.44.1): + vite@7.3.1(sass@1.97.2)(terser@5.44.1): dependencies: - esbuild: 0.25.2 - fdir: 6.4.6(picomatch@4.0.3) + esbuild: 0.27.2 + fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.46.1 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 optionalDependencies: fsevents: 2.3.3 - sass: 1.97.0 + sass: 1.97.2 terser: 5.44.1 - vitefu@1.1.1(vite@7.0.6(sass@1.97.0)(terser@5.44.1)): + vitefu@1.1.1(vite@7.3.1(sass@1.97.2)(terser@5.44.1)): optionalDependencies: - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) - vitest@4.0.16(jsdom@26.1.0)(sass@1.97.0)(terser@5.44.1): + vitest@4.0.16(jsdom@26.1.0)(sass@1.97.2)(terser@5.44.1): dependencies: '@vitest/expect': 4.0.16 - '@vitest/mocker': 4.0.16(vite@7.0.6(sass@1.97.0)(terser@5.44.1)) + '@vitest/mocker': 4.0.16(vite@7.3.1(sass@1.97.2)(terser@5.44.1)) '@vitest/pretty-format': 4.0.16 '@vitest/runner': 4.0.16 '@vitest/snapshot': 4.0.16 @@ -9049,7 +8967,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.0.6(sass@1.97.0)(terser@5.44.1) + vite: 7.3.1(sass@1.97.2)(terser@5.44.1) why-is-node-running: 2.3.0 optionalDependencies: jsdom: 26.1.0 @@ -9223,7 +9141,7 @@ snapshots: workbox-core@7.1.0: {} - workbox-core@7.3.0: {} + workbox-core@7.4.0: {} workbox-expiration@7.1.0: dependencies: @@ -9280,10 +9198,10 @@ snapshots: '@types/trusted-types': 2.0.7 workbox-core: 7.1.0 - workbox-window@7.3.0: + workbox-window@7.4.0: dependencies: '@types/trusted-types': 2.0.7 - workbox-core: 7.3.0 + workbox-core: 7.4.0 wrap-ansi@6.2.0: dependencies: diff --git a/src/lib/chord-editor/action-linter.ts b/src/lib/chord-editor/action-linter.ts new file mode 100644 index 00000000..13e6f730 --- /dev/null +++ b/src/lib/chord-editor/action-linter.ts @@ -0,0 +1,135 @@ +import { linter, type Diagnostic } from "@codemirror/lint"; +import { parsedChordsField } from "./parsed-chords-plugin"; + +export function actionLinter(config?: Parameters[1]) { + const finalConfig: Parameters[1] = { + ...config, + needsRefresh(update) { + return ( + update.startState.field(parsedChordsField) !== + update.state.field(parsedChordsField) + ); + }, + }; + return linter((view) => { + console.log("lint"); + const diagnostics: Diagnostic[] = []; + const parsed = view.state.field(parsedChordsField); + + for (const chord of parsed.chords) { + if (chord.disabled) { + diagnostics.push({ + from: chord.range[0], + to: chord.range[1], + severity: "info", + markClass: "chord-ignored", + message: `Chord disabled`, + }); + } + if (chord.compounds) { + for (const compound of chord.compounds) { + if (compound.actions.length === 0 && compound.parent) { + const replacement = view.state.doc.sliceString( + compound.parent.range[0], + compound.parent.input!.range[1], + ); + diagnostics.push({ + from: compound.range[0], + to: compound.range[1], + severity: "warning", + message: `Compound literal can be replaced with "${replacement}"`, + actions: [ + { + name: "Replace", + apply(view, from, to) { + view.dispatch({ + changes: { + from, + to, + insert: replacement + "|", + }, + }); + }, + }, + ], + }); + } + } + const lastCompound = chord.compounds.at(-1); + if (lastCompound) { + const from = chord.range[0]; + const to = lastCompound.range[1]; + if (lastCompound.parent) { + diagnostics.push({ + from, + to, + severity: "info", + markClass: "chord-child", + message: `Child of ${view.state.doc.sliceString(lastCompound.parent.range[0], lastCompound.parent.range[1])}`, + actions: [ + { + name: "Select Parent", + apply(view) { + view.dispatch({ + selection: { + anchor: lastCompound.parent!.range[0], + }, + scrollIntoView: true, + }); + }, + }, + ], + }); + } else { + diagnostics.push({ + from, + to, + severity: "warning", + message: `Orphan compound`, + }); + } + } + } + if (chord.children) { + diagnostics.push({ + from: chord.range[0], + to: chord.range[1], + severity: "info", + markClass: "chord-parent", + message: `Parent of ${chord.children.length} compound(s)`, + actions: chord.children.map((child) => ({ + name: `Go to ${view.state.doc.sliceString(child.range[0], child.range[1])}`, + apply(view) { + view.dispatch({ + selection: { + anchor: child.range[0], + }, + scrollIntoView: true, + }); + }, + })), + }); + } + if (chord.phrase) { + if (!chord.phrase.originalValue) { + diagnostics.push({ + from: chord.range[0], + to: chord.range[1], + severity: "info", + markClass: "chord-new", + message: `New Chord`, + }); + } else if (chord.phrase.originalValue !== chord.phrase.value) { + diagnostics.push({ + from: chord.range[0], + to: chord.range[1], + severity: "info", + markClass: "chord-unchanged", + message: `Phrase changed`, + }); + } + } + } + return diagnostics; + }, finalConfig); +} diff --git a/src/lib/chord-editor/action-meta-plugin.ts b/src/lib/chord-editor/action-meta-plugin.ts new file mode 100644 index 00000000..446ec2c4 --- /dev/null +++ b/src/lib/chord-editor/action-meta-plugin.ts @@ -0,0 +1,10 @@ +import { KEYMAP_CODES, KEYMAP_IDS } from "$lib/serial/keymap-codes"; +import { derived } from "svelte/store"; +import { reactiveStateField } from "./store-state-field"; + +const actionMeta = derived([KEYMAP_IDS, KEYMAP_CODES], ([ids, codes]) => ({ + ids, + codes, +})); + +export const actionMetaPlugin = reactiveStateField(actionMeta); diff --git a/src/lib/chord-editor/action-plugin.ts b/src/lib/chord-editor/action-plugin.ts index cbf8a10a..b2377fcb 100644 --- a/src/lib/chord-editor/action-plugin.ts +++ b/src/lib/chord-editor/action-plugin.ts @@ -7,33 +7,34 @@ import { } from "@codemirror/view"; import { mount, unmount } from "svelte"; import Action from "$lib/components/Action.svelte"; -import { syntaxTree } from "@codemirror/language"; import type { Range } from "@codemirror/state"; +import { parsedChordsField } from "./parsed-chords-plugin"; +import { iterActions } from "./parse-meta"; export class ActionWidget extends WidgetType { component?: {}; - element?: HTMLElement; constructor(readonly id: string | number) { super(); this.id = id; } - override eq(other: ActionWidget) { + /*override eq(other: ActionWidget) { return this.id == other.id; - } + }*/ toDOM() { - if (!this.element) { - this.element = document.createElement("span"); - this.element.style.paddingInline = "2px"; - - this.component = mount(Action, { - target: this.element, - props: { action: this.id, display: "keys", inText: true }, - }); + if (this.component) { + unmount(this.component); } - return this.element; + const element = document.createElement("span"); + element.style.paddingInline = "2px"; + + this.component = mount(Action, { + target: element, + props: { action: this.id, display: "keys", inText: true }, + }); + return element; } override ignoreEvent() { @@ -50,29 +51,24 @@ export class ActionWidget extends WidgetType { function actionWidgets(view: EditorView) { const widgets: Range[] = []; for (const { from, to } of view.visibleRanges) { - syntaxTree(view.state).iterate({ - from, - to, - enter: (node) => { - if (node.name !== "ExplicitAction") return; - const value = - node.node.getChild("ActionId") ?? - node.node.getChild("HexNumber") ?? - node.node.getChild("DecimalNumber"); - if (!value) return; - if (!node.node.getChild("ExplicitDelimEnd")) { + for (const chord of view.state.field(parsedChordsField).chords) { + if (chord.range[1] < from || chord.range[0] > to) continue; + iterActions(chord, (action) => { + if ( + view.state.selection.ranges.some( + (r) => r.from <= action.range[1] && r.to > action.range[0], + ) + ) { return; } - - const id = view.state.doc.sliceString(value.from, value.to); - let deco = Decoration.replace({ - widget: new ActionWidget( - value.name === "ActionId" ? id : parseInt(id), - ), - }); - widgets.push(deco.range(node.from, node.to)); - }, - }); + if (action.info && action.explicit) { + const deco = Decoration.replace({ + widget: new ActionWidget(action.code), + }); + widgets.push(deco.range(action.range[0], action.range[1])); + } + }); + } } return Decoration.set(widgets); } @@ -89,7 +85,9 @@ export const actionPlugin = ViewPlugin.fromClass( if ( update.docChanged || update.viewportChanged || - syntaxTree(update.startState) != syntaxTree(update.state) + update.selectionSet || + update.startState.field(parsedChordsField) != + update.state.field(parsedChordsField) ) this.decorations = actionWidgets(update.view); } diff --git a/src/lib/chord-editor/action-serializer.ts b/src/lib/chord-editor/action-serializer.ts index d2781d63..de22321b 100644 --- a/src/lib/chord-editor/action-serializer.ts +++ b/src/lib/chord-editor/action-serializer.ts @@ -1,16 +1,308 @@ import { KEYMAP_CODES, type KeyInfo } from "$lib/serial/keymap-codes"; +import type { CharaChordFile } from "$lib/share/chara-file"; +import { syntaxTree } from "@codemirror/language"; +import type { EditorState } from "@codemirror/state"; import { get } from "svelte/store"; +import { + composeChordInput, + hasConcatenator, + hashChord, + willBeValidChordInput, +} from "$lib/serial/chord"; +import type { + ActionMeta, + ChordMeta, + MetaRange, + ParseResult, +} from "./parse-meta"; export function canUseIdAsString(info: KeyInfo): boolean { - return !!info.id && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(info.id); + return !!info.id && /^[^>\n]+$/.test(info.id); } export function actionToValue(action: number | KeyInfo) { const info = typeof action === "number" ? get(KEYMAP_CODES).get(action) : action; if (info && info.id?.length === 1) - return /^[<>\\\s]$/.test(info.id) ? `\\${info.id}` : info.id; + return /^[<>|\\\s]$/.test(info.id) ? `\\${info.id}` : info.id; if (!info || !canUseIdAsString(info)) return `<0x${(info?.code ?? action).toString(16).padStart(2, "0")}>`; return `<${info.id}>`; } + +export function parseChordMeta( + data: EditorState, + ids: Map, + codes: Map, +): ChordMeta[] { + console.time("parseChordTree"); + const result: ChordMeta[] = []; + + let current: ChordMeta = { range: [0, 0], valid: false }; + let actions: ActionMeta[] = []; + let actionRange: MetaRange | undefined = undefined; + + syntaxTree(data) + .cursor() + .iterate( + (node) => { + if (node.name === "Action") { + actionRange = [node.from, node.to]; + } else if (node.name === "ChordPhrase") { + current.phrase = { + range: [node.from, node.to], + value: [], + valid: true, + actions: [], + hasConcatenator: false, + }; + } else if (node.name === "Chord") { + current = { range: [node.from, node.to], valid: false }; + } else if (node.name === "ActionString") { + actions = []; + } else if (node.name === "HexNumber") { + const hexString = data.doc.sliceString(node.from, node.to); + const code = Number.parseInt(hexString, 16); + const parentNode = node.node.parent; + if (parentNode?.type.name === "CompoundLiteral") { + current.compounds ??= []; + current.compounds.push({ + range: [parentNode.from, parentNode.to], + value: code, + actions: [], + valid: true, // TODO: validate compound literal + }); + } else { + const valid = !(Number.isNaN(code) || code < 0 || code > 1023); + actions.push({ + code, + info: codes.get(code), + explicit: true, + valid, + range: actionRange!, + }); + } + } else if ( + node.name === "ActionId" || + node.name === "SingleLetter" || + node.name === "EscapedLetter" + ) { + const id = data.doc.sliceString(node.from, node.to); + const info = ids.get(id); + const value: ActionMeta = { + code: info?.code ?? Number.NaN, + info, + valid: info !== undefined, + range: actionRange!, + }; + if (node.name === "ActionId") { + value.explicit = true; + } + actions.push(value); + } + }, + (node) => { + if (node.name === "Chord") { + result.push(current); + if (current.phrase) { + current.phrase.actions = actions; + current.phrase.value = actions.map(({ code }) => code); + current.phrase.valid = actions.every(({ valid }) => valid); + current.phrase.hasConcatenator = hasConcatenator( + current.phrase.value, + codes, + ); + } + current.valid = + (current.phrase?.valid ?? false) && (current.input?.valid ?? false); + if (!current.valid) { + current.disabled = true; + } + } else if (node.name === "CompoundInput") { + const lastCompound = current.compounds?.at(-1); + current.compounds ??= []; + current.compounds.push({ + range: [node.from, node.to], + value: hashChord( + composeChordInput( + actions.map(({ code }) => code), + lastCompound?.value, + ), + ), + actions, + valid: + willBeValidChordInput( + actions.length, + lastCompound !== undefined, + ) && actions.every(({ valid }) => valid), + }); + } else if (node.name === "ChordInput") { + const lastCompound = current.compounds?.at(-1); + current.input = { + range: [node.from, node.to], + value: composeChordInput( + actions.map(({ code }) => code), + lastCompound?.value, + ), + valid: + willBeValidChordInput( + actions.length, + lastCompound !== undefined, + ) && actions.every(({ valid }) => valid), + actions, + }; + } + }, + ); + + console.timeEnd("parseChordTree"); + return result; +} + +function resolveChordOverrides(chords: ChordMeta[]) { + console.time("resolveOverrides"); + const seen = new Map(); + for (const info of chords) { + if (!info.input || info.disabled) continue; + const key = JSON.stringify(info.input.value); + const override = seen.get(key); + if (override) { + override.overrides ??= []; + override.overrides.push(info); + info.overriddenBy = override; + info.disabled = true; + } else { + seen.set(key, info); + } + } + console.timeEnd("resolveOverrides"); +} + +function resolveChordAliases(chords: ChordMeta[]) { + console.time("resolveAliases"); + const aliases = new Map(); + for (const info of chords) { + if (!info.phrase) continue; + const key = JSON.stringify(info.phrase.value); + const list = aliases.get(key) ?? []; + list.push(info); + aliases.set(key, list); + } + for (const aliasList of aliases.values()) { + if (aliasList.length > 1) { + for (const info of aliasList) { + info.aliases = aliasList.filter((i) => i !== info); + } + } + } + console.timeEnd("resolveAliases"); +} + +function resolveCompoundParents(chords: ChordMeta[]) { + console.time("resolveCompoundParents"); + const compounds = new Map(); + for (const chord of chords) { + if (chord.input && !chord.disabled) { + compounds.set(hashChord(chord.input.value), chord); + } + } + for (const chord of chords) { + if (chord.compounds) { + for (const compound of chord.compounds) { + const parent = compounds.get(compound.value); + if (parent) { + compound.parent = parent; + } + } + const lastCompound = chord.compounds?.at(-1); + if (lastCompound && lastCompound.parent) { + lastCompound.parent.children ??= []; + lastCompound.parent.children.push(chord); + } + } + } + console.timeEnd("resolveCompoundParents"); +} + +export function resolveChanges( + chords: ChordMeta[], + deviceChords: CharaChordFile["chords"], +): CharaChordFile["chords"] { + console.time("resolveChanges"); + const removed: CharaChordFile["chords"] = []; + const info = new Map(); + for (const chord of chords) { + if (chord.input && chord.phrase && !chord.disabled) { + info.set( + JSON.stringify([chord.input.value, chord.phrase?.value ?? []]), + chord, + ); + info.set(JSON.stringify(chord.input.value), chord); + } + } + for (const deviceChord of deviceChords) { + const exact = info.get(JSON.stringify(deviceChord)); + if (exact) { + exact.phrase!.originalValue = exact.phrase!.value; + continue; + } + const byInput = info.get(JSON.stringify(deviceChord[0])); + if (byInput) { + byInput.phrase!.originalValue = deviceChord[1]; + continue; + } + removed.push(deviceChord); + } + + console.timeEnd("resolveChanges"); + return removed; +} + +export function parseCharaChords( + data: EditorState, + ids: Map, + codes: Map, + deviceChords: CharaChordFile["chords"], +): ParseResult { + console.time("parseTotal"); + + const chords = parseChordMeta(data, ids, codes); + resolveChordOverrides(chords); + resolveChordAliases(chords); + resolveCompoundParents(chords); + const removed = resolveChanges(chords, deviceChords); + + /*for (let i = 0; i < metas.length; i++) { + const [, compound] = splitCompound(chords[i]![0]); + if ( + compound !== undefined && + (!compoundInputs.has(compound) || orphanCompounds.has(compound)) + ) { + metas[i]!.orphan = true; + } + } + + const removed: CharaChordFile["chords"] = []; + for (let deviceChord of deviceChords) { + const key = JSON.stringify(deviceChord[0]); + if (!keys.has(key)) { + removed.push(deviceChord); + } else { + const index = keys.get(key)!; + const meta = metas[index]!; + if ( + JSON.stringify(deviceChord[1]) !== + JSON.stringify(chords[keys.get(key)!]![1]) + ) { + meta.originalPhrase = deviceChord[1]; + } else { + meta.unchanged = true; + } + } + }*/ + + console.timeEnd("parseTotal"); + + console.log(chords); + return { chords, removed }; +} diff --git a/src/lib/chord-editor/autocomplete.ts b/src/lib/chord-editor/autocomplete.ts index abb796e5..42697d6d 100644 --- a/src/lib/chord-editor/autocomplete.ts +++ b/src/lib/chord-editor/autocomplete.ts @@ -1,72 +1,39 @@ -import { KEYMAP_CATEGORIES, KEYMAP_CODES } from "$lib/serial/keymap-codes"; -import type { - Completion, - CompletionSection, - CompletionSource, -} from "@codemirror/autocomplete"; -import { derived, get } from "svelte/store"; -import { actionToValue, canUseIdAsString } from "./action-serializer"; +import { + EditorView, + ViewPlugin, + ViewUpdate, + type PluginValue, +} from "@codemirror/view"; +import { syntaxTree } from "@codemirror/language"; +import type { EditorState } from "@codemirror/state"; -const completionSections = derived( - KEYMAP_CATEGORIES, - (categories) => - new Map( - categories.map( - (category) => - [ - category, - { - name: category.name, - } satisfies CompletionSection, - ] as const, - ), - ), -); +export function actionAutocompletePlugin( + query: (query: string | undefined) => void, +) { + return ViewPlugin.fromClass( + class implements PluginValue { + constructor(readonly view: EditorView) {} -export const actionAutocompleteItems = derived( - [KEYMAP_CODES, completionSections], - ([codes, sections]) => - codes - .values() - .map((info) => { - const canUseId = canUseIdAsString(info); - const completionValue = - (canUseId && info.id) || - `0x${info.code.toString(16).padStart(2, "0")}`; - return { - label: - [ - canUseId || !info.id ? undefined : `"${info.id}"`, - info.title, - info.variant?.replace(/^[a-z]/g, (c) => c.toUpperCase()), - ] - .filter(Boolean) - .join(" ") || completionValue, - detail: actionToValue(info), - section: info.category ? sections.get(info.category) : undefined, - info: info.description, - type: "keyword", - apply: completionValue + ">", - } satisfies Completion; - }) - .filter( - (item) => typeof item.label === "string" && item.apply !== undefined, - ) - .toArray(), -); + update(update: ViewUpdate) { + query(this.resolveAutocomplete(update.state)); + } -export const actionAutocomplete = ((context) => { - let word = context.tokenBefore([ - "ExplicitDelimStart", - "ActionId", - "HexNumber", - "DecimalNumber", - ]); - if (!word) return null; - console.log(get(actionAutocompleteItems)); - return { - from: word.type.name === "ExplicitDelimStart" ? word.to : word.from, - validFor: /^({ + create() { + return Decoration.none; + }, + update(decorations, tr) { + const newChords = tr.effects.findLast((e) => e.is(parsedChordsEffect)); + if (!newChords) { + return decorations.map(tr.changes); + } + return newChords.value.meta.map(meta => { + if (meta.originalPhrase) { + return underlineMark.range(meta.from, meta.to); +} +}); + }, + provide: (f) => EditorView.decorations.from(f), +}); diff --git a/src/lib/chord-editor/changes-panel.ts b/src/lib/chord-editor/changes-panel.ts new file mode 100644 index 00000000..cf97f14c --- /dev/null +++ b/src/lib/chord-editor/changes-panel.ts @@ -0,0 +1,39 @@ +import type { EditorState } from "@codemirror/state"; +import { EditorView, showPanel, type Panel } from "@codemirror/view"; +import { parsedChordsField } from "./parsed-chords-plugin"; + +function getChanges(state: EditorState): string { + const parsed = state.field(parsedChordsField); + const added = parsed.chords.reduce( + (acc, chord) => + acc + (chord.phrase && chord.phrase.originalValue === undefined ? 1 : 0), + 0, + ); + const changed = parsed.chords.reduce( + (acc, chord) => + acc + + (chord.phrase && + chord.phrase.originalValue && + chord.phrase.originalValue !== chord.phrase.value + ? 1 + : 0), + 0, + ); + const removed = parsed.removed.length; + return `+${added} ~${changed} -${removed} (${parsed.chords.length} total)`; +} + +function wordCountPanel(view: EditorView): Panel { + let dom = document.createElement("div"); + dom.textContent = getChanges(view.state); + return { + dom, + update(update) { + dom.textContent = getChanges(update.state); + }, + }; +} + +export function changesPanel() { + return showPanel.of(wordCountPanel); +} diff --git a/src/lib/chord-editor/changes-plugin.ts b/src/lib/chord-editor/changes-plugin.ts deleted file mode 100644 index 7fd73597..00000000 --- a/src/lib/chord-editor/changes-plugin.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { - EditorView, - ViewPlugin, - ViewUpdate, - type PluginValue, -} from "@codemirror/view"; - -export const changesPlugin = ViewPlugin.fromClass( - class implements PluginValue { - constructor(readonly view: EditorView) {} - - update(update: ViewUpdate) {} - }, - { - eventHandlers: {}, - }, -); diff --git a/src/lib/chord-editor/chord-delim-plugin.ts b/src/lib/chord-editor/chord-delim-plugin.ts index 089d35b4..2a844487 100644 --- a/src/lib/chord-editor/chord-delim-plugin.ts +++ b/src/lib/chord-editor/chord-delim-plugin.ts @@ -26,7 +26,7 @@ export class DelimWidget extends WidgetType { toDOM() { if (!this.element) { - this.element = document.createElement("span"); + /*this.element = document.createElement("span"); this.element.innerHTML = " ⇛" + (this.hasConcatenator ? "" : " "); this.element.style.scale = "1.8"; @@ -41,7 +41,9 @@ export class DelimWidget extends WidgetType { props: { action: 574, display: "keys", inText: true, ghost: true }, }); this.element.appendChild(button); - } + }*/ + this.element = document.createElement("div"); + this.element.style.breakAfter = "column"; } return this.element; } diff --git a/src/lib/chord-editor/chord-sync-plugin.ts b/src/lib/chord-editor/chord-sync-plugin.ts new file mode 100644 index 00000000..d0a110dc --- /dev/null +++ b/src/lib/chord-editor/chord-sync-plugin.ts @@ -0,0 +1,32 @@ +import type { CharaChordFile } from "$lib/share/chara-file"; +import { StateEffect, StateField } from "@codemirror/state"; + +export const chordSyncEffect = StateEffect.define(); + +export const deviceChordField = StateField.define({ + create() { + return []; + }, + update(value, transaction) { + // save initial device chords + // compare new device chords with initial device chords + // take changed/new/removed chords + // compare current editor chords with initial device chords + // compare two change sets + // apply removals if the chord didn't change on either end + // apply + return ( + transaction.effects.findLast((it) => it.is(chordSyncEffect))?.value ?? + value + ); + }, + compare(a, b) { + return JSON.stringify(a) === JSON.stringify(b); + }, + toJSON(value) { + return value; + }, + fromJSON(value) { + return value; + }, +}); diff --git a/src/lib/chord-editor/chords-grammar-plugin.ts b/src/lib/chord-editor/chords-grammar-plugin.ts index 6d524be5..071be7f1 100644 --- a/src/lib/chord-editor/chords-grammar-plugin.ts +++ b/src/lib/chord-editor/chords-grammar-plugin.ts @@ -5,7 +5,6 @@ import { HighlightStyle, } from "@codemirror/language"; import { styleTags, tags } from "@lezer/highlight"; -import { actionAutocomplete } from "./autocomplete"; export const chordHighlightStyle = HighlightStyle.define([ { @@ -51,7 +50,5 @@ export const chordLanguage = LRLanguage.define({ }); export function chordLanguageSupport() { - return new LanguageSupport(chordLanguage, [ - chordLanguage.data.of({ autocomplete: actionAutocomplete }), - ]); + return new LanguageSupport(chordLanguage, [chordLanguage.data.of({})]); } diff --git a/src/lib/chord-editor/chords.grammar b/src/lib/chord-editor/chords.grammar index c63d9952..c0283079 100644 --- a/src/lib/chord-editor/chords.grammar +++ b/src/lib/chord-editor/chords.grammar @@ -1,27 +1,43 @@ @top Program { Chord* } -ExplicitAction { ExplicitDelimStart (HexNumber | DecimalNumber | ActionId) ExplicitDelimEnd } +ExplicitAction { ExplicitDelimStart (HexNumber | ActionId) ExplicitDelimEnd } EscapedSingleAction { Escape EscapedLetter } Action { SingleLetter | ExplicitAction | EscapedSingleAction } -ActionString { Action* } -ChordInput { (ActionString CompoundDelim)* ActionString } + +ActionString { Action+ } + +CompoundLiteral { CompoundDelim HexNumber CompoundDelim } +CompoundInput { ActionString CompoundDelim } + +ChordInput { CompoundLiteral? CompoundInput* ActionString } ChordPhrase { ActionString } + Chord { ChordInput PhraseDelim ChordPhrase ChordDelim } +@skip { + Space +} + @tokens { - @precedence {HexNumber, DecimalNumber} - @precedence {CompoundDelim, PhraseDelim, ExplicitDelimStart, ChordDelim, SingleLetter} - @precedence {EscapedLetter} + @precedence { HexNumber, ActionId } + @precedence { Space, Escape } + @precedence { Space, SingleLetter } + @precedence { Escape, SingleLetter } + @precedence { CompoundDelim, SingleLetter } + @precedence { ActionId, Space } + @precedence { EscapedLetter, Space } + + Space {" "} ExplicitDelimStart {"<"} ExplicitDelimEnd {">"} - CompoundDelim {"+>"} + CompoundDelim {"|"} PhraseDelim {"=>"} Escape { "\\" } HexNumber { "0x" $[a-fA-F0-9]+ } - DecimalNumber { $[0-9]+ } - ActionId { $[a-zA-Z_]$[a-zA-Z0-9_]* } - SingleLetter { ![\\] } - EscapedLetter { ![] } - ChordDelim { ($[\n] | @eof) } + ActionId { ![\n>]+ } + SingleLetter { ![\n<] } + EscapedLetter { ![\n] } + ChordDelim { ("\n" | @eof) } } +@detectDelim diff --git a/src/lib/chord-editor/parse-meta.ts b/src/lib/chord-editor/parse-meta.ts new file mode 100644 index 00000000..ac21336d --- /dev/null +++ b/src/lib/chord-editor/parse-meta.ts @@ -0,0 +1,172 @@ +import type { KeyInfo } from "$lib/serial/keymap-codes"; +import type { CharaChordFile } from "$lib/share/chara-file"; +import type { ChangeDesc } from "@codemirror/state"; + +export type MetaRange = [from: number, to: number]; + +function mapMetaRange(range: MetaRange, change: ChangeDesc): MetaRange { + const newFrom = change.mapPos(range[0]); + const newTo = change.mapPos(range[1]); + if (newFrom === range[0] && newTo === range[1]) { + return range; + } + return [newFrom, newTo]; +} + +export interface ActionMeta { + code: number; + info?: KeyInfo; + explicit?: boolean; + range: MetaRange; + valid: boolean; +} + +function mapActionMeta(action: ActionMeta, change: ChangeDesc): ActionMeta { + const newRange = mapMetaRange(action.range, change); + if (newRange === action.range) { + return action; + } + return { + ...action, + range: newRange, + }; +} + +function mapArray( + array: T[], + change: ChangeDesc, + mapFn: (action: T, change: ChangeDesc) => T, +): T[] { + let changed = false; + const newArray = array.map((value) => { + const newValue = mapFn(value, change); + if (newValue !== value) { + changed = true; + return newValue; + } + return value; + }); + if (changed) { + return newArray; + } + return array; +} + +export interface ActionStringMeta { + range: MetaRange; + value: T; + valid: boolean; + actions: ActionMeta[]; +} + +function mapActionStringMeta>( + actionString: T, + change: ChangeDesc, +) { + const newRange = mapMetaRange(actionString.range, change); + const newActions = mapArray(actionString.actions, change, mapActionMeta); + if (newRange === actionString.range && newActions === actionString.actions) { + return actionString; + } + return { + ...actionString, + range: newRange, + actions: newActions, + }; +} + +export interface PhraseMeta extends ActionStringMeta { + hasConcatenator: boolean; + originalValue?: number[]; +} + +export interface CompoundMeta extends ActionStringMeta { + parent?: ChordMeta; +} + +export interface InputMeta extends ActionStringMeta {} + +export interface ChordMeta { + range: MetaRange; + valid: boolean; + disabled?: boolean; + compounds?: CompoundMeta[]; + input?: InputMeta; + phrase?: PhraseMeta; + children?: ChordMeta[]; + overrides?: ChordMeta[]; + aliases?: ChordMeta[]; + overriddenBy?: ChordMeta; +} + +export function mapChordMeta(chord: ChordMeta, change: ChangeDesc): ChordMeta { + const newRange = mapMetaRange(chord.range, change); + const newCompounds = chord.compounds + ? mapArray(chord.compounds, change, mapActionStringMeta) + : undefined; + const newInput = chord.input + ? mapActionStringMeta(chord.input, change) + : undefined; + const newPhrase = chord.phrase + ? mapActionStringMeta(chord.phrase, change) + : undefined; + if ( + newRange === chord.range && + newCompounds === chord.compounds && + newInput === chord.input && + newPhrase === chord.phrase + ) { + return chord; + } + + const newChord: ChordMeta = { + ...chord, + range: newRange, + }; + if (newCompounds) newChord.compounds = newCompounds; + if (newInput) newChord.input = newInput; + if (newPhrase) newChord.phrase = newPhrase; + return newChord; +} + +export interface ParseResult { + chords: ChordMeta[]; + removed: CharaChordFile["chords"]; +} + +export function mapParseResult( + result: ParseResult, + change: ChangeDesc, +): ParseResult { + const newChords = mapArray(result.chords, change, mapChordMeta); + if (newChords === result.chords) { + return result; + } + return { + ...result, + chords: newChords, + }; +} + +export function iterActions( + chord: ChordMeta, + callback: (action: ActionMeta) => void, +) { + if (chord.input) { + for (const action of chord.input.actions) { + callback(action); + } + } + if (chord.compounds) { + for (const compound of chord.compounds) { + for (const action of compound.actions) { + callback(action); + } + } + } + if (chord.phrase) { + for (const action of chord.phrase.actions) { + callback(action); + } + } +} diff --git a/src/lib/chord-editor/parsed-chords-plugin.ts b/src/lib/chord-editor/parsed-chords-plugin.ts new file mode 100644 index 00000000..2a3160f6 --- /dev/null +++ b/src/lib/chord-editor/parsed-chords-plugin.ts @@ -0,0 +1,30 @@ +import { StateField } from "@codemirror/state"; +import { parseCharaChords } from "./action-serializer"; +import { actionMetaPlugin } from "./action-meta-plugin"; +import { syntaxTree } from "@codemirror/language"; +import { deviceChordField } from "./chord-sync-plugin"; +import { mapParseResult, type ParseResult } from "./parse-meta"; + +export const parsedChordsField = StateField.define({ + create() { + return { + chords: [], + removed: [], + }; + }, + update(value, transaction) { + const tree = syntaxTree(transaction.state); + const ids = transaction.state.field(actionMetaPlugin.field).ids; + const codes = transaction.state.field(actionMetaPlugin.field).codes; + const deviceChords = transaction.state.field(deviceChordField); + if ( + tree !== syntaxTree(transaction.startState) || + ids !== transaction.startState.field(actionMetaPlugin.field).ids || + codes !== transaction.startState.field(actionMetaPlugin.field).codes || + deviceChords !== transaction.startState.field(deviceChordField) + ) { + return parseCharaChords(transaction.state, ids, codes, deviceChords); + } + return mapParseResult(value, transaction.changes); + }, +}); diff --git a/src/lib/chord-editor/persistent-state-plugin.ts b/src/lib/chord-editor/persistent-state-plugin.ts new file mode 100644 index 00000000..15db9849 --- /dev/null +++ b/src/lib/chord-editor/persistent-state-plugin.ts @@ -0,0 +1,133 @@ +import { + EditorView, + highlightActiveLine, + keymap, + lineNumbers, + ViewPlugin, + ViewUpdate, +} from "@codemirror/view"; +import { + history, + historyField, + historyKeymap, + standardKeymap, +} from "@codemirror/commands"; +import { debounceTime, mergeMap, Subject } from "rxjs"; +import { EditorState, type EditorStateConfig } from "@codemirror/state"; +import { lintGutter } from "@codemirror/lint"; +import { + chordHighlightStyle, + chordLanguageSupport, +} from "./chords-grammar-plugin"; +import { actionLinter } from "./action-linter"; +import { actionAutocompletePlugin } from "./autocomplete"; +import { delimPlugin } from "./chord-delim-plugin"; +import { actionPlugin } from "./action-plugin"; +import { syntaxHighlighting } from "@codemirror/language"; +import { deviceChordField } from "./chord-sync-plugin"; +import { actionMetaPlugin } from "./action-meta-plugin"; +import { parsedChordsField } from "./parsed-chords-plugin"; +import { changesPanel } from "./changes-panel"; +import { + parseCompressed, + stringifyCompressed, +} from "$lib/serial/serialization"; + +const serializedFields = { + history: historyField, + deviceChords: deviceChordField, +}; + +export interface EditorConfig { + rawCode?: boolean; + storeName: string; + autocomplete(query: string | undefined): void; +} + +export async function loadPersistentState( + params: EditorConfig, +): Promise { + const stored = localStorage.getItem(params.storeName); + const config = { + extensions: [ + actionMetaPlugin.plugin, + deviceChordField, + parsedChordsField, + changesPanel(), + lintGutter(), + params.rawCode ? [lineNumbers()] : [delimPlugin, actionPlugin], + chordLanguageSupport(), + actionLinter({ + delay: 100, + markerFilter(diagnostics) { + return diagnostics.filter((it) => it.from !== it.to); + }, + }), + actionAutocompletePlugin(params.autocomplete), + persistentStatePlugin(params.storeName), + history(), + syntaxHighlighting(chordHighlightStyle), + highlightActiveLine(), + EditorView.theme({ + ".cm-line": { + borderBottom: "1px solid transparent", + caretColor: "var(--md-sys-color-on-surface)", + }, + ".cm-scroller": { + overflow: "auto", + width: "100%", + fontFamily: "inherit !important", + gap: "8px", + }, + ".cm-content": { + flex: 1, + }, + ".cm-cursor": { + borderColor: "var(--md-sys-color-on-surface)", + }, + }), + keymap.of([...standardKeymap, ...historyKeymap]), + ], + } satisfies EditorStateConfig; + + if (stored) { + try { + const parsed = await parseCompressed(new Blob([stored])); + return EditorState.fromJSON(parsed, config, serializedFields); + } catch (e) { + console.error("Failed to parse persistent state:", e); + } + } + return EditorState.create(config); +} + +export function persistentStatePlugin(storeName: string) { + return ViewPlugin.fromClass( + class { + updateSubject = new Subject(); + subscription = this.updateSubject + .pipe( + debounceTime(500), + mergeMap(() => + stringifyCompressed(this.view.state.toJSON(serializedFields)), + ), + mergeMap((blob) => blob.text()), + ) + .subscribe((value) => { + localStorage.setItem(storeName, value); + }); + + constructor(readonly view: EditorView) {} + + update(update: ViewUpdate) { + if (update.state !== update.startState) { + this.updateSubject.next(); + } + } + + destroy() { + this.subscription.unsubscribe(); + } + }, + ); +} diff --git a/src/lib/chord-editor/store-state-field.ts b/src/lib/chord-editor/store-state-field.ts new file mode 100644 index 00000000..42ff8098 --- /dev/null +++ b/src/lib/chord-editor/store-state-field.ts @@ -0,0 +1,35 @@ +import { StateEffect, StateField } from "@codemirror/state"; +import { EditorView, ViewPlugin } from "@codemirror/view"; +import { get, type Readable } from "svelte/store"; + +export function reactiveStateField(store: Readable) { + const effect = StateEffect.define(); + const field = StateField.define({ + create() { + return get(store); + }, + update(value, transaction) { + return ( + transaction.effects.findLast((it) => it.is(effect))?.value ?? value + ); + }, + }); + const plugin = ViewPlugin.fromClass( + class { + unsubscribe: () => void; + + constructor(readonly view: EditorView) { + this.unsubscribe = store.subscribe((value) => { + setTimeout(() => { + view.dispatch({ effects: effect.of(value) }); + }); + }); + } + + destroy() { + this.unsubscribe(); + } + }, + ); + return { field, plugin: [field, plugin] }; +} diff --git a/src/lib/chord-editor/test.txt b/src/lib/chord-editor/test.txt index dd377111..3bafe340 100644 --- a/src/lib/chord-editor/test.txt +++ b/src/lib/chord-editor/test.txt @@ -1,16 +1,16 @@ -.= => => -;ims => <0x219> --; => <0x23e>_<0x23e> -.;g => <0x23e>...<0x23e> -'dg => <0x23e>'<0x23e> -'gl => <0x23e>'ll<0x23e> -'ar => <0x23e>'re<0x23e> -'gs => <0x23e>'s<0x23e> -'ev => <0x23e>'ve<0x23e> --; => <0x23e><0x223>-<0x223> -; => <0x23e><0x223><0x23d><0x223> -;g => <0x23e><0x223><0x223> -deg => <0x23e>ed<0x23e> -;gr => <0x23e>er<0x23e> -;es => <0x23e>es<0x23e> -;est => <0x23e>est<0x23e> +a|.==>t=t +;ims=<0x219> +-;=><0x23e>_<0x23e> +.;g=><0x23e>...<0x23e> +'dg=><0x23e>'<0x23e> +'gl=><0x23e>'ll<0x23e> +'ar=><0x23e>'re<0x23e> +'gs=><0x23e>'s<0x23e> +'ev=><0x23e>'ve<0x23e> +-;=><0x23e><0x223>-<0x223> +;=><0x23e><0x223><0x23d><0x223> +;g=><0x23e><0x223><0x223> +deg=><0x23e>ed<0x23e> +;gr=><0x23e>er<0x23e> +;es=><0x23e>es<0x23e> +;est=><0x23e>est<0x23e> diff --git a/src/lib/components/Action.svelte b/src/lib/components/Action.svelte index 3fa99fe3..82abc83d 100644 --- a/src/lib/components/Action.svelte +++ b/src/lib/components/Action.svelte @@ -8,10 +8,12 @@ let { action, display, + ignoreIcon = false, inText = false, }: { action: string | number | KeyInfo; display: "inline-keys" | "keys" | "verbose"; + ignoreIcon?: boolean; inText?: boolean; } = $props(); @@ -30,6 +32,7 @@ ? ({ code: 1024, id: action } satisfies KeyInfo) : action), ); + let icon = $derived(ignoreIcon ? undefined : info.icon); let dynamicMapping = $derived(info.keyCode && $osLayout.get(info.keyCode)); let hasPopover = $derived( !retrievedInfo || !info.id || info.title || info.description, @@ -63,7 +66,7 @@ {#snippet kbdText()} {dynamicMapping ?? - info.icon ?? + icon ?? info.display ?? info.id ?? `0x${info.code.toString(16)}`} @@ -71,7 +74,7 @@ {#snippet kbdSnippet(withPopover = true)} 1023} @@ -91,7 +94,7 @@ class:left={info.variant === "left"} class:right={info.variant === "right"}>{dynamicMapping} - {:else if !info.icon && info.id?.length === 1} + {:else if !icon && info.id?.length === 1} 1023} {@attach hasPopover ? actionTooltip(popover) : null} @@ -155,21 +158,50 @@ text-decoration: line-through; } - $variant-offset: 12px; - $variant-padding: calc(2px + $variant-offset); $variant-color: color-mix( in srgb, var(--md-sys-color-on-surface) 50%, transparent ); + .left, + .right { + background-color: transparent; + + &::before { + position: absolute; + inset: 0; + outline: 2px dashed + color-mix(in srgb, var(--bg-color), var(--md-sys-color-outline) 40%); + outline-offset: -2px; + border-radius: var(--border-radius); + content: ""; + } + } + + $cutoff: 60%; + .left { - padding-inline-end: $variant-padding; - text-shadow: $variant-offset 0 2px $variant-color; + background-image: linear-gradient( + to right, + var(--bg-color) $cutoff, + transparent $cutoff + ); + + &::before { + clip-path: inset(0 0 0 $cutoff); + } } .right { - padding-inline-start: $variant-padding; - text-shadow: -$variant-offset 0 2px $variant-color; + background-image: linear-gradient( + to left, + var(--bg-color) $cutoff, + transparent $cutoff + ); + + &::before { + clip-path: inset(0 $cutoff 0 0); + } } .inline-kbd { diff --git a/src/lib/components/layout/ActionList.svelte b/src/lib/components/layout/ActionList.svelte index 15d116af..ad0149d7 100644 --- a/src/lib/components/layout/ActionList.svelte +++ b/src/lib/components/layout/ActionList.svelte @@ -19,13 +19,17 @@ let { currentAction = undefined, nextAction = undefined, + queryFilter = undefined, + ignoreIcon, autofocus = false, onselect, onclose, }: { currentAction?: number; + queryFilter?: string; nextAction?: number; autofocus?: boolean; + ignoreIcon?: boolean; onselect?: (id: number) => void; onclose?: () => void; } = $props(); @@ -43,6 +47,14 @@ createIndex($KEYMAP_CODES); }); + let didClear = true; + $effect(() => { + if (queryFilter !== undefined || !didClear) { + searchBox.value = queryFilter ?? ""; + search(); + } + }); + async function createIndex(codes: Map) { for (const [, action] of codes) { await index?.addAsync( @@ -60,6 +72,7 @@ (category) => [category, []] as [KeymapCategory, KeyInfo[]], ), ); + didClear = searchBox.value === ""; const result = searchBox.value === "" ? Array.from($KEYMAP_CODES.keys()) @@ -167,7 +180,7 @@
  • Action code is out of range
  • {/if} {/if} - {#each results as [category, actions] (category)} + {#each results as [category, actions] (actions)} {#if actions.length > 0}

    {category.name}

    @@ -191,7 +204,7 @@ } : undefined} > - + {/each} diff --git a/src/lib/serial/chord.ts b/src/lib/serial/chord.ts index 532e2ca3..8b18030f 100644 --- a/src/lib/serial/chord.ts +++ b/src/lib/serial/chord.ts @@ -1,4 +1,5 @@ import { compressActions, decompressActions } from "../serialization/actions"; +import type { KeyInfo } from "./keymap-codes"; export interface Chord { actions: number[]; @@ -56,6 +57,103 @@ export function deserializeActions(native: bigint): number[] { return actions; } +const compoundHashItems = 3; +const maxChordInputItems = 12; +const actionBits = 10; +const actionMask = (1 << actionBits) - 1; + +/** + * Applies the compound value to a **valid** chord input + */ +export function applyCompound(actions: number[], compound: number): number[] { + const result = [...actions]; + for (let i = 0; i < compoundHashItems; i++) { + result[i] = (compound >>> (i * actionBits)) & actionMask; + } + result[compoundHashItems] = 0; + return result; +} + +/** + * Extracts the compound value from a chord input, if present + */ +export function splitCompound( + actions: number[], +): [inputs: number[], compound: number | undefined] { + if (actions[compoundHashItems] != 0) { + return [ + actions.slice( + Math.max( + 0, + actions.findIndex((it) => it !== 0), + ), + ), + undefined, + ]; + } + + let compound = 0; + for (let i = 0; i < compoundHashItems; i++) { + compound |= (actions[i] ?? 0) << (i * actionBits); + } + + return [ + actions.slice( + actions.findIndex((it, i) => i > compoundHashItems && it !== 0), + ), + compound === 0 ? undefined : compound, + ]; +} + +export function willBeValidChordInput( + inputCount: number, + hasCompound: boolean, +): boolean { + return ( + inputCount > 0 && + inputCount <= maxChordInputItems - (hasCompound ? compoundHashItems + 1 : 0) + ); +} + +const ACTION_JOIN = 574; +const ACTION_KSC_00 = 256; + +export function hasConcatenator( + actions: number[], + ids: Map, +): boolean { + const lastAction = actions.at(-1); + for (const action of actions) { + if (!ids.get(action)?.printable) { + if (actions.length == 0) { + return false; + } + return lastAction == ACTION_JOIN; + } + } + return lastAction != ACTION_KSC_00; +} + +/** + * Composes a chord input from a list of actions and an optional compound value + * to a valid chord input + */ +export function composeChordInput( + actions: number[], + compound?: number, +): number[] { + const result = [ + ...Array.from( + { + length: Math.max(0, maxChordInputItems - actions.length), + }, + () => 0, + ), + ...actions.slice(0, maxChordInputItems).sort((a, b) => a - b), + ]; + return compound !== undefined ? applyCompound(result, compound) : result; +} + /** * Hashes a chord input the same way as CCOS */ @@ -72,5 +170,6 @@ export function hashChord(actions: number[]) { if ((hash & 0xff) === 0xff) { hash ^= 0xff; } - return hash & 0x3fff_ffff; + hash &= 0x3fff_ffff; + return hash === 0 ? 1 : hash; } diff --git a/src/lib/serial/connection.ts b/src/lib/serial/connection.ts index f0196aa1..55ecf933 100644 --- a/src/lib/serial/connection.ts +++ b/src/lib/serial/connection.ts @@ -55,7 +55,10 @@ export const syncStatus: Writable< "done" | "error" | "downloading" | "uploading" > = writable("done"); -export const deviceMeta = writable(undefined); +export const deviceMeta = persistentWritable( + "current-meta", + undefined, +); export interface ProgressInfo { max: number; diff --git a/src/lib/style/_kbd.scss b/src/lib/style/_kbd.scss index 0ab2e5da..a4ae2ba4 100644 --- a/src/lib/style/_kbd.scss +++ b/src/lib/style/_kbd.scss @@ -1,22 +1,22 @@ kbd { - display: inline-flex; - justify-content: center; - align-items: center; - margin-block: 6px; - border-radius: 4px; - - //border: 1px solid currentcolor; - background: color-mix( + --bg-color: color-mix( in srgb, var(--md-sys-color-surface-variant) 50%, transparent ); - padding: 4px; + --border-radius: 4px; + display: inline-flex; + position: relative; + justify-content: center; + align-items: center; + margin-block: 6px; + border-radius: var(--border-radius); + background: var(--bg-color); + padding: 4px; height: 20px; color: currentcolor; font-weight: normal; - font-size: 14px; &.icon { diff --git a/src/routes/(app)/config/cv2/+page.svelte b/src/routes/(app)/config/cv2/+page.svelte index 9713d609..aa167895 100644 --- a/src/routes/(app)/config/cv2/+page.svelte +++ b/src/routes/(app)/config/cv2/+page.svelte @@ -2,93 +2,224 @@ import { chords } from "$lib/undo-redo"; import { EditorView } from "codemirror"; import { actionToValue } from "$lib/chord-editor/action-serializer"; - import { actionPlugin } from "$lib/chord-editor/action-plugin"; - import { delimPlugin } from "$lib/chord-editor/chord-delim-plugin"; - import { - drawSelection, - dropCursor, - highlightActiveLine, - highlightSpecialChars, - keymap, - } from "@codemirror/view"; - import { history, standardKeymap } from "@codemirror/commands"; import "$lib/chord-editor/chords.grammar"; - import { - chordHighlightStyle, - chordLanguageSupport, - } from "$lib/chord-editor/chords-grammar-plugin"; - import { syntaxHighlighting } from "@codemirror/language"; - import { autocompletion } from "@codemirror/autocomplete"; import { persistentWritable } from "$lib/storage"; import ActionList from "$lib/components/layout/ActionList.svelte"; + import { + composeChordInput, + hashChord, + splitCompound, + } from "$lib/serial/chord"; + import { loadPersistentState } from "$lib/chord-editor/persistent-state-plugin"; + import { parsedChordsField } from "$lib/chord-editor/parsed-chords-plugin"; + import type { CharaChordFile } from "$lib/share/chara-file"; + import { chordSyncEffect } from "$lib/chord-editor/chord-sync-plugin"; + import { KEYMAP_IDS, type KeyInfo } from "$lib/serial/keymap-codes"; + + let queryFilter: string | undefined = $state(undefined); const rawCode = persistentWritable("chord-editor-raw-code", false); const showEdits = persistentWritable("chord-editor-show-edits", true); - let originalDoc = $derived( - $chords + const denseSpacing = persistentWritable("chord-editor-spacing", false); + + let editor: HTMLDivElement | undefined = $state(undefined); + let view: EditorView; + + $effect(() => { + if (!editor) return; + const viewPromise = loadPersistentState({ + rawCode: $rawCode, + storeName: "chord-editor-state-storage", + autocomplete(query) { + queryFilter = query; + }, + }).then( + (state) => + new EditorView({ + parent: editor, + state, + }), + ); + viewPromise.then((it) => (view = it)); + return () => viewPromise.then((it) => it.destroy()); + }); + + function regenerate() { + const doc = $chords .map((chord) => { + const [actions, compound] = splitCompound(chord.actions); return ( - chord.actions - .filter((it) => it !== 0) - .map((it) => actionToValue(it)) - .join("") + + (compound ? "|0x" + compound.toString(16) + "|" : "") + + actions.map((it) => actionToValue(it)).join("") + "=>" + chord.phrase.map((it) => actionToValue(it)).join("") ); }) - .join("\n"), - ); - let editor: HTMLDivElement | undefined = $state(undefined); - let view: EditorView; + .join("\n"); + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: doc }, + effects: chordSyncEffect.of( + $chords.map((chord) => [chord.actions, chord.phrase] as const), + ), + }); + } - $effect(() => { - if (!editor) return; - view = new EditorView({ - parent: editor, - doc: originalDoc, - extensions: [ - ...($rawCode ? [] : [delimPlugin, actionPlugin]), - chordLanguageSupport(), - autocompletion({ icons: false, selectOnOpen: true }), - history(), - dropCursor(), - syntaxHighlighting(chordHighlightStyle), - highlightActiveLine(), - drawSelection(), - highlightSpecialChars(), - keymap.of(standardKeymap), - ], + function largeFile() { + const chordCount = 100000; + const maxPhraseLength = 100; + const maxInputLength = 8; + const compoundChance = 0.05; + + const actions = [...$KEYMAP_IDS.values()]; + function randomAction(): KeyInfo { + return actions[Math.floor(actions.length * Math.random())]!; + } + + const backup: [KeyInfo[][], KeyInfo[]][] = Array.from( + { length: chordCount }, + () => + [ + [ + Array.from( + { length: Math.floor(Math.random() * maxInputLength) + 1 }, + randomAction, + ), + ], + Array.from( + { + length: Math.floor(Math.log(Math.random() * maxPhraseLength)) + 1, + }, + randomAction, + ), + ] as const, + ); + for (const chord of backup) { + if (Math.random() < compoundChance) { + chord[0] = [ + ...backup[Math.floor(backup.length * Math.random())]![0], + ...chord[0], + ]; + } + } + + const doc = backup + .map(([inputs, phrase]) => { + return ( + inputs + .map((input) => input.map((it) => actionToValue(it)).join("")) + .join("|") + + "=>" + + phrase.map((it) => actionToValue(it)).join("") + ); + }) + .join("\n"); + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: doc }, + effects: chordSyncEffect.of( + $chords.map((chord) => [chord.actions, chord.phrase] as const), + ), }); - return () => view.destroy(); - }); + } + + function loadBackup(event: Event) { + const input = event.target as HTMLInputElement; + if (!input.files || input.files.length === 0) return; + const file = input.files[0]; + const reader = new FileReader(); + reader.onload = (e) => { + try { + const content = e.target?.result as string; + const backup: CharaChordFile = JSON.parse(content); + const doc = backup.chords + .map((chord) => { + const [actions, compound] = splitCompound(chord[0]); + return ( + (compound + ? "<0x" + compound.toString(16).padStart(8, "0") + ">" + : "") + + actions.map((it) => actionToValue(it)).join("") + + "=>" + + chord[1].map((it) => actionToValue(it)).join("") + ); + }) + .join("\n"); + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: doc }, + }); + } catch (err) { + alert("Failed to load backup: " + err); + } + }; + reader.readAsText(file); + } + + function downloadBackup() { + const backup: CharaChordFile = { + charaVersion: 1, + type: "chords", + chords: view.state.field(parsedChordsField).result, + }; + console.log(JSON.stringify(backup)); + const blob = new Blob([JSON.stringify(backup)], { + type: "application/json", + }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = "chord-backup.json"; + a.click(); + URL.revokeObjectURL(url); + } - - - -
    - -
    +
    +
    + + + + + + + +
    + +
    +
    + +