diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e39a0521..319def1c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,6 +27,9 @@ jobs: - name: install frontend dependencies run: npm ci + - name: audit complete dependency lockfile + run: npm audit + - name: check frontend run: npm run check diff --git a/package-lock.json b/package-lock.json index 7a59f0ac..1399fabc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "markpad", - "version": "2.6.13", + "version": "2.6.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "markpad", - "version": "2.6.13", + "version": "2.6.14", "license": "MIT", "dependencies": { "@tauri-apps/api": "^2", @@ -16,26 +16,26 @@ "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-updater": "^2.10.1", "@types/dompurify": "^3.0.5", - "dompurify": "^3.3.1", + "dompurify": "3.4.12", "highlight.js": "^11.11.1", "highlightjs-svelte": "^1.0.6", "katex": "^0.16.27", - "mermaid": "^11.12.2", + "mermaid": "^11.16.0", "monaco-editor": "^0.55.1", "monaco-vim": "^0.4.4", "node-stream-zip": "^1.15.0", "yaml": "^2.9.0" }, "devDependencies": { - "@sveltejs/adapter-static": "^3.0.6", - "@sveltejs/kit": "^2.9.0", - "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.70.2", + "@sveltejs/vite-plugin-svelte": "^5.1.1", "@tauri-apps/cli": "^2", - "svelte": "^5.0.0", - "svelte-check": "^4.0.0", + "svelte": "^5.56.8", + "svelte-check": "^4.7.4", "tsx": "^4.22.4", "typescript": "~5.6.2", - "vite": "^6.0.3" + "vite": "^6.4.3" } }, "node_modules/@antfu/install-pkg": { @@ -57,55 +57,10 @@ "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", "license": "MIT" }, - "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", - "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/gast": "11.0.3", - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/@chevrotain/cst-dts-gen/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, - "node_modules/@chevrotain/gast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", - "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/@chevrotain/gast/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, - "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", - "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", - "license": "Apache-2.0" - }, "node_modules/@chevrotain/types": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", - "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", - "license": "Apache-2.0" - }, - "node_modules/@chevrotain/utils": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", - "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "license": "Apache-2.0" }, "node_modules/@esbuild/aix-ppc64": { @@ -618,12 +573,12 @@ } }, "node_modules/@mermaid-js/parser": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.3.tgz", - "integrity": "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.2.0.tgz", + "integrity": "sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==", "license": "MIT", "dependencies": { - "langium": "3.3.1" + "@chevrotain/types": "~11.1.2" } }, "node_modules/@polka/url": { @@ -634,9 +589,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", - "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.3.tgz", + "integrity": "sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==", "cpu": [ "arm" ], @@ -648,9 +603,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", - "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.3.tgz", + "integrity": "sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==", "cpu": [ "arm64" ], @@ -662,9 +617,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", - "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.3.tgz", + "integrity": "sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==", "cpu": [ "arm64" ], @@ -676,9 +631,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", - "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.3.tgz", + "integrity": "sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==", "cpu": [ "x64" ], @@ -690,9 +645,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", - "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.3.tgz", + "integrity": "sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==", "cpu": [ "arm64" ], @@ -704,9 +659,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", - "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.3.tgz", + "integrity": "sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==", "cpu": [ "x64" ], @@ -718,13 +673,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", - "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.3.tgz", + "integrity": "sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -732,13 +690,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", - "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.3.tgz", + "integrity": "sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -746,13 +707,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", - "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.3.tgz", + "integrity": "sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -760,13 +724,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", - "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.3.tgz", + "integrity": "sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -774,13 +741,16 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", - "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.3.tgz", + "integrity": "sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -788,13 +758,16 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", - "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.3.tgz", + "integrity": "sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -802,13 +775,16 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", - "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.3.tgz", + "integrity": "sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -816,13 +792,16 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", - "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.3.tgz", + "integrity": "sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -830,13 +809,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", - "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.3.tgz", + "integrity": "sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -844,13 +826,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", - "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.3.tgz", + "integrity": "sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -858,13 +843,16 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", - "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.3.tgz", + "integrity": "sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -872,13 +860,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", - "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.3.tgz", + "integrity": "sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -886,13 +877,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", - "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.3.tgz", + "integrity": "sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -900,9 +894,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", - "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.3.tgz", + "integrity": "sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==", "cpu": [ "x64" ], @@ -914,9 +908,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", - "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.3.tgz", + "integrity": "sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==", "cpu": [ "arm64" ], @@ -928,9 +922,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", - "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.3.tgz", + "integrity": "sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==", "cpu": [ "arm64" ], @@ -942,9 +936,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", - "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.3.tgz", + "integrity": "sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==", "cpu": [ "ia32" ], @@ -956,9 +950,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", - "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.3.tgz", + "integrity": "sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==", "cpu": [ "x64" ], @@ -970,9 +964,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", - "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.3.tgz", + "integrity": "sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==", "cpu": [ "x64" ], @@ -991,9 +985,9 @@ "license": "MIT" }, "node_modules/@sveltejs/acorn-typescript": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.8.tgz", - "integrity": "sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.11.tgz", + "integrity": "sha512-LFuZUkjJ9iF7JZye/aG5XM0SFcQ5VyL0oVX4WJ9dc0Va3R3s0OauX1BESVCb+YN/ol8TAfqGDDAQsTG627Y5kw==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1011,24 +1005,23 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.49.4", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.49.4.tgz", - "integrity": "sha512-JFtOqDoU0DI/+QSG8qnq5bKcehVb3tCHhOG4amsSYth5/KgO4EkJvi42xSAiyKmXAAULW1/Zdb6lkgGEgSxdZg==", + "version": "2.70.2", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.70.2.tgz", + "integrity": "sha512-RzRoRpuR2KXqc5yMO0akQHDZeT4AslOlznGITURsqHaVbtyYP4Wn3eE3gxj9JcDyNYO0crkxhdwFHc+2vkVm6w==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", - "@sveltejs/acorn-typescript": "^1.0.5", + "@sveltejs/acorn-typescript": "^1.0.9", "@types/cookie": "^0.6.0", - "acorn": "^8.14.1", + "acorn": "^8.16.0", "cookie": "^0.6.0", - "devalue": "^5.3.2", + "devalue": "^5.8.1", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", - "sade": "^1.8.1", - "set-cookie-parser": "^2.6.0", + "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "bin": { @@ -1039,10 +1032,10 @@ }, "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", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.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" + "typescript": "^5.3.3 || ^6.0.0", + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "peerDependenciesMeta": { "@opentelemetry/api": { @@ -1053,6 +1046,16 @@ } } }, + "node_modules/@sveltejs/load-config": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sveltejs/load-config/-/load-config-0.2.1.tgz", + "integrity": "sha512-5m3B2cbqQ4TbwW6Xkh66Ntw6dD7gNc77cCxABTTesWcq9jxIzMgTk97pZx5vEtvQx8iokgi7GIphqZe+PGwcZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + } + }, "node_modules/@sveltejs/vite-plugin-svelte": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", @@ -1601,9 +1604,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -1619,10 +1622,20 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT" }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1632,9 +1645,9 @@ } }, "node_modules/aria-query": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", - "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", + "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1651,38 +1664,6 @@ "node": ">= 0.4" } }, - "node_modules/chevrotain": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", - "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/cst-dts-gen": "11.0.3", - "@chevrotain/gast": "11.0.3", - "@chevrotain/regexp-to-ast": "11.0.3", - "@chevrotain/types": "11.0.3", - "@chevrotain/utils": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/chevrotain-allstar": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", - "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", - "license": "MIT", - "dependencies": { - "lodash-es": "^4.17.21" - }, - "peerDependencies": { - "chevrotain": "^11.0.0" - } - }, - "node_modules/chevrotain/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -1725,9 +1706,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { @@ -1744,9 +1725,9 @@ } }, "node_modules/cytoscape": { - "version": "3.33.1", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", - "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz", + "integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==", "license": "MIT", "engines": { "node": ">=0.10" @@ -2242,9 +2223,9 @@ } }, "node_modules/dagre-d3-es": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", - "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", "license": "MIT", "dependencies": { "d3": "^7.9.0", @@ -2252,9 +2233,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.19", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", "license": "MIT" }, "node_modules/debug": { @@ -2286,30 +2267,41 @@ } }, "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", "license": "ISC", "dependencies": { "robust-predicates": "^3.0.2" } }, "node_modules/devalue": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.1.tgz", - "integrity": "sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.9.0.tgz", + "integrity": "sha512-RWrqdArjvPbsATEhOPUo6Wndc/iWnkWKlhIrdlF3zMMYo/c3CVtoaVAyLtWxz5h8nSlkHzxnzV2uLydPXmtF+A==", "dev": true, "license": "MIT" }, "node_modules/dompurify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", - "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", + "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, + "node_modules/es-toolkit": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", + "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks", + "tests/types" + ] + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", @@ -2360,13 +2352,21 @@ "license": "MIT" }, "node_modules/esrap": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.1.tgz", - "integrity": "sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.3.0.tgz", + "integrity": "sha512-GQ/7RN8uOtEfNpzZzBMTzW9JBcX42oaSVtPzdF+6cEL8pqIL094iUpr9jzYGn4O4P/1S60dJ6izyT8F4LYARng==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "peerDependencies": { + "@typescript-eslint/types": "^8.2.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/types": { + "optional": true + } } }, "node_modules/fdir": { @@ -2454,9 +2454,9 @@ } }, "node_modules/katex": { - "version": "0.16.27", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.27.tgz", - "integrity": "sha512-aeQoDkuRWSqQN6nSvVCEFvfXdqo1OQiCmmW1kc9xSdjutPv7BGO7pqY9sQRJpMOGrEdfDgF2TfRXe5eUAD2Waw==", + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -2484,22 +2484,6 @@ "node": ">=6" } }, - "node_modules/langium": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", - "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", - "license": "MIT", - "dependencies": { - "chevrotain": "~11.0.3", - "chevrotain-allstar": "~0.3.0", - "vscode-languageserver": "~9.0.1", - "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.0.8" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/layout-base": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", @@ -2514,9 +2498,9 @@ "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, "node_modules/magic-string": { @@ -2542,31 +2526,32 @@ } }, "node_modules/mermaid": { - "version": "11.12.2", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.2.tgz", - "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==", + "version": "11.16.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.16.0.tgz", + "integrity": "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==", "license": "MIT", "dependencies": { - "@braintree/sanitize-url": "^7.1.1", - "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^0.6.3", + "@braintree/sanitize-url": "^7.1.2", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.2.0", "@types/d3": "^7.4.3", - "cytoscape": "^3.29.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.3", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.13", - "dayjs": "^1.11.18", - "dompurify": "^3.2.5", - "katex": "^0.16.22", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.20", + "dompurify": "^3.3.3", + "es-toolkit": "^1.45.1", + "katex": "^0.16.45", "khroma": "^2.1.0", - "lodash-es": "^4.17.21", - "marked": "^16.2.1", + "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", - "uuid": "^11.1.0" + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "node_modules/mermaid/node_modules/marked": { @@ -2603,15 +2588,6 @@ "marked": "14.0.0" } }, - "node_modules/monaco-editor/node_modules/dompurify": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", - "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" - } - }, "node_modules/monaco-vim": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/monaco-vim/-/monaco-vim-0.4.4.tgz", @@ -2648,9 +2624,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "dev": true, "funding": [ { @@ -2704,9 +2680,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, "license": "MIT", "engines": { @@ -2744,9 +2720,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", "dev": true, "funding": [ { @@ -2764,7 +2740,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -2787,19 +2763,19 @@ } }, "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", - "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.3.tgz", + "integrity": "sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@types/estree": "1.0.9" }, "bin": { "rollup": "dist/bin/rollup" @@ -2809,31 +2785,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.1", - "@rollup/rollup-android-arm64": "4.55.1", - "@rollup/rollup-darwin-arm64": "4.55.1", - "@rollup/rollup-darwin-x64": "4.55.1", - "@rollup/rollup-freebsd-arm64": "4.55.1", - "@rollup/rollup-freebsd-x64": "4.55.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", - "@rollup/rollup-linux-arm-musleabihf": "4.55.1", - "@rollup/rollup-linux-arm64-gnu": "4.55.1", - "@rollup/rollup-linux-arm64-musl": "4.55.1", - "@rollup/rollup-linux-loong64-gnu": "4.55.1", - "@rollup/rollup-linux-loong64-musl": "4.55.1", - "@rollup/rollup-linux-ppc64-gnu": "4.55.1", - "@rollup/rollup-linux-ppc64-musl": "4.55.1", - "@rollup/rollup-linux-riscv64-gnu": "4.55.1", - "@rollup/rollup-linux-riscv64-musl": "4.55.1", - "@rollup/rollup-linux-s390x-gnu": "4.55.1", - "@rollup/rollup-linux-x64-gnu": "4.55.1", - "@rollup/rollup-linux-x64-musl": "4.55.1", - "@rollup/rollup-openbsd-x64": "4.55.1", - "@rollup/rollup-openharmony-arm64": "4.55.1", - "@rollup/rollup-win32-arm64-msvc": "4.55.1", - "@rollup/rollup-win32-ia32-msvc": "4.55.1", - "@rollup/rollup-win32-x64-gnu": "4.55.1", - "@rollup/rollup-win32-x64-msvc": "4.55.1", + "@rollup/rollup-android-arm-eabi": "4.62.3", + "@rollup/rollup-android-arm64": "4.62.3", + "@rollup/rollup-darwin-arm64": "4.62.3", + "@rollup/rollup-darwin-x64": "4.62.3", + "@rollup/rollup-freebsd-arm64": "4.62.3", + "@rollup/rollup-freebsd-x64": "4.62.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.3", + "@rollup/rollup-linux-arm-musleabihf": "4.62.3", + "@rollup/rollup-linux-arm64-gnu": "4.62.3", + "@rollup/rollup-linux-arm64-musl": "4.62.3", + "@rollup/rollup-linux-loong64-gnu": "4.62.3", + "@rollup/rollup-linux-loong64-musl": "4.62.3", + "@rollup/rollup-linux-ppc64-gnu": "4.62.3", + "@rollup/rollup-linux-ppc64-musl": "4.62.3", + "@rollup/rollup-linux-riscv64-gnu": "4.62.3", + "@rollup/rollup-linux-riscv64-musl": "4.62.3", + "@rollup/rollup-linux-s390x-gnu": "4.62.3", + "@rollup/rollup-linux-x64-gnu": "4.62.3", + "@rollup/rollup-linux-x64-musl": "4.62.3", + "@rollup/rollup-openbsd-x64": "4.62.3", + "@rollup/rollup-openharmony-arm64": "4.62.3", + "@rollup/rollup-win32-arm64-msvc": "4.62.3", + "@rollup/rollup-win32-ia32-msvc": "4.62.3", + "@rollup/rollup-win32-x64-gnu": "4.62.3", + "@rollup/rollup-win32-x64-msvc": "4.62.3", "fsevents": "~2.3.2" } }, @@ -2875,9 +2851,9 @@ "license": "MIT" }, "node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.2.tgz", + "integrity": "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==", "dev": true, "license": "MIT" }, @@ -2913,23 +2889,24 @@ "license": "MIT" }, "node_modules/svelte": { - "version": "5.46.3", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.46.3.tgz", - "integrity": "sha512-Y5juST3x+/ySty5tYJCVWa6Corkxpt25bUZQHqOceg9xfMUtDsFx6rCsG6cYf1cA6vzDi66HIvaki0byZZX95A==", + "version": "5.56.8", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.56.8.tgz", + "integrity": "sha512-PY8LOw7xP6c8IOiVqdo0sbbZVYhXRSfklOQLAUyGBKqjTX0wx/z4l/9J+PmBpmlLnxzEb1NqltxQ5/wZme/Cmg==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", - "@sveltejs/acorn-typescript": "^1.0.5", + "@sveltejs/acorn-typescript": "^1.0.10", "@types/estree": "^1.0.5", + "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", - "aria-query": "^5.3.1", + "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", - "devalue": "^5.5.0", + "devalue": "^5.8.1", "esm-env": "^1.2.1", - "esrap": "^2.2.1", + "esrap": "^2.2.12", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", @@ -2940,13 +2917,14 @@ } }, "node_modules/svelte-check": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.5.tgz", - "integrity": "sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.7.4.tgz", + "integrity": "sha512-IW9ot9YqAoyv8FvyN+eb4ZTe8zgcKZrJLNYU6dzSKkGwEBsSPc4K7lmQ8bKn8W2YMXM6WDfZSSVOaGtekyUfOQ==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", + "@sveltejs/load-config": "^0.2.1", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", @@ -2960,7 +2938,7 @@ }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", - "typescript": ">=5.0.0" + "typescript": "^5.0.0 || ^6.0.0" } }, "node_modules/tinyexec": { @@ -3532,22 +3510,22 @@ "license": "MIT" }, "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", + "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "license": "MIT", "bin": { - "uuid": "dist/esm/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", "dev": true, "license": "MIT", "dependencies": { @@ -3639,55 +3617,6 @@ } } }, - "node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", - "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", - "license": "MIT", - "dependencies": { - "vscode-languageserver-protocol": "3.17.5" - }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "license": "MIT", - "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "license": "MIT" - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "license": "MIT" - }, - "node_modules/vscode-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", - "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", - "license": "MIT" - }, "node_modules/yaml": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", diff --git a/package.json b/package.json index c4f9621f..f2b2f637 100644 --- a/package.json +++ b/package.json @@ -25,25 +25,29 @@ "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-updater": "^2.10.1", "@types/dompurify": "^3.0.5", - "dompurify": "^3.3.1", + "dompurify": "3.4.12", "highlight.js": "^11.11.1", "highlightjs-svelte": "^1.0.6", "katex": "^0.16.27", - "mermaid": "^11.12.2", + "mermaid": "^11.16.0", "monaco-editor": "^0.55.1", "monaco-vim": "^0.4.4", "node-stream-zip": "^1.15.0", "yaml": "^2.9.0" }, "devDependencies": { - "@sveltejs/adapter-static": "^3.0.6", - "@sveltejs/kit": "^2.9.0", - "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.70.2", + "@sveltejs/vite-plugin-svelte": "^5.1.1", "@tauri-apps/cli": "^2", - "svelte": "^5.0.0", - "svelte-check": "^4.0.0", + "svelte": "^5.56.8", + "svelte-check": "^4.7.4", "tsx": "^4.22.4", "typescript": "~5.6.2", - "vite": "^6.0.3" + "vite": "^6.4.3" + }, + "overrides": { + "cookie": "0.7.2", + "dompurify": "3.4.12" } -} \ No newline at end of file +} diff --git a/scripts/documentLoadFailure.test.ts b/scripts/documentLoadFailure.test.ts new file mode 100644 index 00000000..8fc579d0 --- /dev/null +++ b/scripts/documentLoadFailure.test.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const session = readFileSync('src/lib/sessions/documentSession.svelte.ts', 'utf8'); + +test('a transient missing-file read error preserves the open tab', () => { + assert.doesNotMatch(session, /tabManager\.closeTab/); + assert.match(session, /options\.onError\('Error loading file', error\);/); +}); diff --git a/scripts/fileAssociations.test.ts b/scripts/fileAssociations.test.ts new file mode 100644 index 00000000..03ade7b9 --- /dev/null +++ b/scripts/fileAssociations.test.ts @@ -0,0 +1,13 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const config = JSON.parse(readFileSync('src-tauri/tauri.conf.json', 'utf8')) as { + bundle: { fileAssociations: Array<{ ext: string[] }> }; +}; + +test('installer advertises only Markdown file associations', () => { + const extensions = config.bundle.fileAssociations.flatMap((association) => association.ext); + assert.deepEqual(extensions, ['md', 'markdown']); + assert.equal(extensions.includes('txt'), false); +}); diff --git a/scripts/liveModeWatchedPath.test.ts b/scripts/liveModeWatchedPath.test.ts new file mode 100644 index 00000000..7f009744 --- /dev/null +++ b/scripts/liveModeWatchedPath.test.ts @@ -0,0 +1,20 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const runtime = readFileSync('src-tauri/src/window_runtime.rs', 'utf8'); +const viewer = readFileSync('src/lib/MarkdownViewer.svelte', 'utf8'); + +test('Live Mode routes a watcher notification to its watched path', () => { + assert.match(runtime, /emit_to\(event_label\.as_str\(\), "file-changed", watched_path\.clone\(\)\)/); + assert.match(viewer, /await appWindow\.listen\('file-changed', \(event\) => \{/); + assert.match(viewer, /const changedPath = event\.payload as string;/); + assert.match(viewer, /if \(!liveMode \|\| !currentFile \|\| changedPath !== currentFile\) return;/); +}); + +test('Live Mode follows the active file instead of retaining a previous tab watcher', () => { + assert.match(viewer, /if \(liveMode && currentFile\) \{\n\t\t\tinvoke\('watch_file', \{ path: currentFile \}\)/); + assert.doesNotMatch(readFileSync('src/lib/sessions/documentSession.svelte.ts', 'utf8'), /isLiveMode\(\)\) invoke\('watch_file'/); + const toggleLiveMode = viewer.slice(viewer.indexOf('function toggleLiveMode'), viewer.indexOf('async function saveImageAs')); + assert.doesNotMatch(toggleLiveMode, /loadMarkdown\(/); +}); diff --git a/scripts/macosOpenDocumentPaths.test.ts b/scripts/macosOpenDocumentPaths.test.ts new file mode 100644 index 00000000..6b373ab7 --- /dev/null +++ b/scripts/macosOpenDocumentPaths.test.ts @@ -0,0 +1,16 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const runtime = readFileSync('src-tauri/src/window_runtime.rs', 'utf8'); +const tauriLib = readFileSync('src-tauri/src/lib.rs', 'utf8'); +const viewer = readFileSync('src/lib/MarkdownViewer.svelte', 'utf8'); + +test('macOS open-document events preserve every delivered file path', () => { + assert.match(runtime, /startup_files: Mutex>/); + assert.match(tauriLib, /for url in urls/); + assert.match(tauriLib, /startup_files\.lock\(\)\.unwrap\(\)\.push\(path_str\.clone\(\)\)/); + assert.match(runtime, /startup_files\.lock\(\)\.unwrap\(\)\.drain\(\.\.\)\.collect\(\)/); + assert.match(runtime, /for path in startup_files\.into_iter\(\)\.rev\(\)/); + assert.match(viewer, /for \(const path of args\) await loadMarkdown\(path\);/); +}); diff --git a/scripts/macosPdfExport.test.ts b/scripts/macosPdfExport.test.ts new file mode 100644 index 00000000..d563937c --- /dev/null +++ b/scripts/macosPdfExport.test.ts @@ -0,0 +1,16 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +test('all Markpad webviews may invoke Tauri native printing', () => { + const capability = JSON.parse(readFileSync('src-tauri/capabilities/default.json', 'utf8')) as { + windows: string[]; + permissions: string[]; + }; + + assert.deepEqual(capability.windows, ['main', 'installer', 'window-*']); + assert.ok( + capability.permissions.includes('core:webview:allow-print'), + 'macOS replaces window.print() with Tauri native printing, which requires this permission', + ); +}); diff --git a/scripts/openMultipleFiles.test.ts b/scripts/openMultipleFiles.test.ts new file mode 100644 index 00000000..3efbbd33 --- /dev/null +++ b/scripts/openMultipleFiles.test.ts @@ -0,0 +1,12 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const viewer = readFileSync('src/lib/MarkdownViewer.svelte', 'utf8'); +const selectFile = viewer.slice(viewer.indexOf('async function selectFile'), viewer.indexOf('async function reloadFromDisk')); + +test('Open File accepts multiple documents and loads each selected path', () => { + assert.match(selectFile, /multiple: true/); + assert.match(selectFile, /const paths = Array\.isArray\(selected\) \? selected : \[selected\];/); + assert.match(selectFile, /for \(const path of paths\) await loadMarkdown\(path\);/); +}); diff --git a/scripts/previewScrollSync.test.ts b/scripts/previewScrollSync.test.ts index 731ec681..da147f5b 100644 --- a/scripts/previewScrollSync.test.ts +++ b/scripts/previewScrollSync.test.ts @@ -19,8 +19,12 @@ test('editor emits and applies pixel segment scroll positions', () => { assert.match(editor, /type ScrollSyncPosition = \{\s*section: 'frontmatter' \| 'body';\s*ratio: number;\s*\}/); assert.match(editor, /onscrollsync\?: \(position: ScrollSyncPosition\) => void/); assert.match(editor, /function getEditorFrontMatterScrollEnd\(\)/); + assert.match(editor, /function getEditorContentScrollMax\(\)/); assert.match(editor, /function getEditorScrollSyncPosition\(\)/); assert.match(editor, /export function syncScrollToPosition\(position: ScrollSyncPosition\)/); + assert.match(editor, /editor\.getContentHeight\(\) - layout\.height/); + assert.match(editor, /getEditorScrollSyncPosition\(\)[\s\S]*getEditorContentScrollMax\(\)/); + assert.match(editor, /syncScrollToPosition\(position: ScrollSyncPosition\)[\s\S]*getEditorContentScrollMax\(\)/); assert.match(editor, /onscrollsync\?\.\(getEditorScrollSyncPosition\(\)\)/); assert.doesNotMatch(editor, /onscrollsync\?\.\(position\.lineNumber, ratio\)/); assert.doesNotMatch(editor, /export function syncScrollToLine/); diff --git a/scripts/previewWidth.test.ts b/scripts/previewWidth.test.ts new file mode 100644 index 00000000..8634ceea --- /dev/null +++ b/scripts/previewWidth.test.ts @@ -0,0 +1,49 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +import { + DEFAULT_PREVIEW_MAX_WIDTH, + getPreviewContentWidth, + MAX_PREVIEW_MAX_WIDTH, + MIN_PREVIEW_MAX_WIDTH, + normalizePreviewMaxWidth, +} from '../src/lib/utils/previewWidth.js'; + +const settingsSource = readFileSync(new URL('../src/lib/stores/settings.svelte.ts', import.meta.url), 'utf8'); +const viewerSource = readFileSync(new URL('../src/lib/MarkdownViewer.svelte', import.meta.url), 'utf8'); + +test('preview width defaults and clamps persisted numeric values', () => { + assert.equal(DEFAULT_PREVIEW_MAX_WIDTH, 880); + assert.equal(normalizePreviewMaxWidth(null), DEFAULT_PREVIEW_MAX_WIDTH); + assert.equal(normalizePreviewMaxWidth('not-a-number'), DEFAULT_PREVIEW_MAX_WIDTH); + assert.equal(normalizePreviewMaxWidth('639'), MIN_PREVIEW_MAX_WIDTH); + assert.equal(normalizePreviewMaxWidth('1601'), MAX_PREVIEW_MAX_WIDTH); + assert.equal(normalizePreviewMaxWidth('921.8'), 922); +}); + +test('preview width accepts only finite numeric values', () => { + assert.equal(normalizePreviewMaxWidth(Number.NaN), DEFAULT_PREVIEW_MAX_WIDTH); + assert.equal(normalizePreviewMaxWidth(Number.POSITIVE_INFINITY), DEFAULT_PREVIEW_MAX_WIDTH); + assert.equal(normalizePreviewMaxWidth(1200), 1200); +}); + +test('full mode has no configured content-width cap', () => { + assert.equal(getPreviewContentWidth(1200, false), 1200); + assert.equal(getPreviewContentWidth(1200, true), null); +}); + +test('settings load, persist, and reset the preview width through one normalizer', () => { + assert.match(settingsSource, /previewMaxWidth = \$state\(DEFAULT_PREVIEW_MAX_WIDTH\)/); + assert.match(settingsSource, /localStorage\.getItem\('preview\.maxWidth'\)/); + assert.match(settingsSource, /normalizePreviewMaxWidth\(savedPreviewMaxWidth\)/); + assert.match(settingsSource, /localStorage\.setItem\('preview\.maxWidth', String\(this\.previewMaxWidth\)\)/); + assert.match(settingsSource, /resetPreviewMaxWidth\(\)[\s\S]*this\.previewMaxWidth = DEFAULT_PREVIEW_MAX_WIDTH/); +}); + +test('preview layout derives width and ToC geometry from the same preference', () => { + assert.match(viewerSource, /getPreviewContentWidth\(settings\.previewMaxWidth, isFullWidth\)/); + assert.match(viewerSource, /viewerWidth - previewContentWidth/); + assert.match(viewerSource, /--preview-max-width:/); + assert.match(viewerSource, /max-width: var\(--preview-max-width, 880px\)/); +}); diff --git a/scripts/reloadOpenToolbar.test.ts b/scripts/reloadOpenToolbar.test.ts index b7830656..194660df 100644 --- a/scripts/reloadOpenToolbar.test.ts +++ b/scripts/reloadOpenToolbar.test.ts @@ -24,10 +24,10 @@ test('preview-level open shortcut handles Ctrl/Cmd+O outside Monaco without doub assert.match(markdownViewer, /cmdOrCtrl[\s\S]*key === 'o'[\s\S]*selectFile\(\)/); }); -test('editor toolbar delegates to Monaco actions and exposes expected Markdown commands', () => { +test('editor toolbar forwards Monaco actions and optional payloads', () => { assert.match(markdownViewer, /import EditorToolbar from '\.\/components\/EditorToolbar\.svelte'/); - assert.match(markdownViewer, / editorPane\?\.runEditorAction\(actionId\)\}/); - assert.match(editor, /export function runEditorAction\(actionId: string\)/); + assert.match(markdownViewer, / editorPane\?\.runEditorAction\(actionId, payload\)\}/); + assert.match(editor, /export function runEditorAction\(actionId: string, payload\?: any\)/); for (const actionId of [ 'fmt-bold', diff --git a/scripts/scrollSyncInput.test.ts b/scripts/scrollSyncInput.test.ts new file mode 100644 index 00000000..bbbd5373 --- /dev/null +++ b/scripts/scrollSyncInput.test.ts @@ -0,0 +1,11 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const editor = readFileSync('src/lib/components/Editor.svelte', 'utf8'); +const syncEffect = editor.slice(editor.indexOf('if (editor && onscrollsync)'), editor.indexOf('\n\t$effect(() => {', editor.indexOf('if (editor && onscrollsync)') + 1)); + +test('typing does not initiate split scroll synchronization', () => { + assert.match(syncEffect, /editor\.onDidScrollChange/); + assert.doesNotMatch(syncEffect, /onDidChangeCursorPosition/); +}); diff --git a/scripts/taskToggleMemory.test.ts b/scripts/taskToggleMemory.test.ts index cbd9bf25..c7317311 100644 --- a/scripts/taskToggleMemory.test.ts +++ b/scripts/taskToggleMemory.test.ts @@ -3,12 +3,33 @@ import { readFileSync } from 'node:fs'; import test from 'node:test'; const session = readFileSync(new URL('../src/lib/sessions/documentSession.svelte.ts', import.meta.url), 'utf8'); +const markdownProcessing: string = readFileSync(new URL('../src/lib/utils/markdown.ts', import.meta.url), 'utf8'); +const viewer = readFileSync(new URL('../src/lib/MarkdownViewer.svelte', import.meta.url), 'utf8'); test('preview task toggles transform the active in-memory buffer before saving', () => { const taskToggle = session.match(/async function toggleTaskCheckbox[\s\S]*?\n\t}\n\n\treturn/); assert.ok(taskToggle); assert.doesNotMatch(taskToggle[0], /read_file_content/); assert.match(taskToggle[0], /const raw = tab\.rawContent;/); + assert.match(taskToggle[0], /getMarkdownBodyWithoutFrontMatter\(raw\)/); + assert.match(taskToggle[0], /body\.slice\(0, offset\)\.split\('\\n'\)\.length/); + assert.match(taskToggle[0], /(?:\[-\+\*\]|\\d\+\[\.\)\])/); assert.match(taskToggle[0], /tabManager\.updateTabRawContent\(tab\.id, updated\);/); assert.match(taskToggle[0], /await saveContent\(tab\.id\)/); }); + +test('preview task toggles use the renderer source line instead of checkbox order', () => { + const viewerToggle = viewer.match(/async function toggleTaskCheckbox[\s\S]*?\n\t}\n\n/); + assert.ok(viewerToggle); + assert.match(viewerToggle[0], /closest\('li'\)\?\.getAttribute\('data-sourcepos'\)/); + assert.match(viewerToggle[0], /documentSession\.toggleTaskCheckbox\(sourceLine, nowChecked\)/); + assert.doesNotMatch(viewerToggle[0], /allBoxes/); +}); + +test('preview task processing trusts the Markdown renderer task marker', () => { + const taskProcessing = markdownProcessing.match(/function processTaskItems[\s\S]*?\n}\n\nexport function processMarkdownHtml/); + assert.ok(taskProcessing); + assert.match(taskProcessing[0], /input\.hasAttribute\("data-task-checkbox"\)/); + assert.match(taskProcessing[0], /input\.setAttribute\("disabled", ""\)/); + assert.match(markdownProcessing, /input\.removeAttribute\("disabled"\)/); +}); diff --git a/scripts/toolbarCustomizationWiring.test.ts b/scripts/toolbarCustomizationWiring.test.ts index 1af4c54a..fd581013 100644 --- a/scripts/toolbarCustomizationWiring.test.ts +++ b/scripts/toolbarCustomizationWiring.test.ts @@ -63,9 +63,13 @@ test('settings modal uses a dedicated resize handle instead of native CSS resize assert.match(settingsComponent, /\.settings-modal[\s\S]*max-height:/); }); -test('settings modal can be dragged by the header and resized from every edge', () => { +test('settings modal starts dragging only from the non-interactive header surface', () => { assert.match(settingsComponent, /handleSettingsModalDragPointerDown/); - assert.match(settingsComponent, /class="settings-header"[\s\S]*onpointerdown=\{handleSettingsModalDragPointerDown\}/); + assert.match(settingsComponent, /class="settings-modal"[\s\S]*onpointerdown=\{handleSettingsModalDragPointerDown\}/); + assert.match(settingsComponent, /closest\('\.settings-header'\)/); + assert.doesNotMatch(settingsComponent, /class="settings-header"[^>]*onpointerdown=/); + assert.match(settingsComponent, /isSettingsHeaderInteractiveTarget\(e\.target\)/); + assert.match(settingsComponent, /settingsResizeHandles/); for (const handleClass of ['resize-n', 'resize-ne', 'resize-e', 'resize-se', 'resize-s', 'resize-sw', 'resize-w', 'resize-nw']) { assert.match(settingsComponent, new RegExp(`className: '${handleClass}'`)); diff --git a/scripts/windowStartupHandle.test.ts b/scripts/windowStartupHandle.test.ts new file mode 100644 index 00000000..151f7b7d --- /dev/null +++ b/scripts/windowStartupHandle.test.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const backend = readFileSync('src-tauri/src/lib.rs', 'utf8'); + +test('startup reuses the window handle returned by the builder', () => { + assert.match(backend, /let window = window_builder\.build\(\)\?;/); + assert.doesNotMatch(backend, /app\.get_webview_window\(label\)\.unwrap\(\)/); +}); diff --git a/scripts/windowTitleCapability.test.ts b/scripts/windowTitleCapability.test.ts new file mode 100644 index 00000000..78c0a8ef --- /dev/null +++ b/scripts/windowTitleCapability.test.ts @@ -0,0 +1,14 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +test('all Markpad windows may update their native title', () => { + const capability = JSON.parse(readFileSync('src-tauri/capabilities/default.json', 'utf8')) as { + permissions: string[]; + }; + + assert.ok( + capability.permissions.includes('core:window:allow-set-title'), + 'window tags and active document names call appWindow.setTitle(), which requires this permission', + ); +}); diff --git a/scripts/workflowSecurityAudit.test.ts b/scripts/workflowSecurityAudit.test.ts new file mode 100644 index 00000000..eb890c7f --- /dev/null +++ b/scripts/workflowSecurityAudit.test.ts @@ -0,0 +1,10 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const workflow = readFileSync('.github/workflows/test.yml', 'utf8'); + +test('pull-request checks reject vulnerabilities anywhere in the resolved lockfile', () => { + assert.match(workflow, /name: audit complete dependency lockfile[\s\S]*run: npm audit(?:\s|$)/); + assert.doesNotMatch(workflow, /npm audit --omit=dev/); +}); diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 955f6753..c41704e0 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -13,7 +13,9 @@ "opener:allow-open-url", "opener:allow-open-path", "dialog:default", + "core:webview:allow-print", "core:window:allow-start-dragging", + "core:window:allow-set-title", "core:window:allow-minimize", "core:window:allow-toggle-maximize", "core:window:allow-close", @@ -25,4 +27,4 @@ "updater:default", "process:default" ] -} \ No newline at end of file +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 99ce9cd8..e751350f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -198,6 +198,47 @@ mod tests { ); } + #[test] + fn task_list_checkbox_is_emitted_at_the_start_of_its_list_item() { + let html = convert_markdown("- [ ] open task\n- [x] completed task\n"); + assert!( + html.contains("
  • open task
  • "), + "unexpected task-list HTML: {html}", + ); + assert!( + html.contains("
  • completed task
  • "), + "unexpected task-list HTML: {html}", + ); + } + + #[test] + fn raw_html_checkboxes_are_not_marked_as_tasks() { + let html = convert_markdown("- raw control\n"); + assert!( + !html.contains("data-task-checkbox"), + "raw HTML control was incorrectly marked as a task: {html}", + ); + } + + #[test] + fn nested_and_quoted_task_checkboxes_are_marked() { + let html = convert_markdown("- [ ] parent\n - [x] nested\n\n> - [ ] quoted\n"); + assert_eq!( + html.matches("data-task-checkbox").count(), + 3, + "unexpected task-list HTML: {html}", + ); + } + + #[test] + fn multiline_wikilinks_do_not_shift_task_source_positions() { + let html = convert_markdown("[[#first\nsecond|alias]]\n- [ ] task\n"); + assert!( + html.contains("data-task-checkbox"), + "task source position was shifted by a multiline wikilink: {html}", + ); + } + #[test] fn embed_protection_survives_longer_backtick_runs_earlier_in_the_doc() { // A 4-backtick inline sample desynchronized the old regex pairing and @@ -303,6 +344,11 @@ mod tests { fs::remove_dir_all(root).unwrap(); fs::remove_dir_all(outside).unwrap(); } + + #[test] + fn theme_slug_collapses_punctuation_runs() { + assert_eq!(theme_slug("SynthWave '84"), "synthwave-84"); + } } mod setup; @@ -654,7 +700,37 @@ fn convert_markdown(content: &str) -> String { options.render.hardbreaks = true; options.render.sourcepos = true; - markdown_to_html(&processed_links, &options) + let html = markdown_to_html(&processed_links, &options); + annotate_task_checkboxes(html, content) +} + +fn annotate_task_checkboxes(html: String, markdown: &str) -> String { + let task_item = Regex::new( + r#"
  • (?)"#, + ) + .unwrap(); + let task_source = Regex::new(r"^\s*(?:>\s*)*(?:[-+*]|\d+[.)])\s+\[[ xX]\](?:\s|$)").unwrap(); + + task_item + .replace_all(&html, |captures: &Captures| { + let line = captures["line"].parse::().unwrap_or_default(); + let source_line = markdown.lines().nth(line.saturating_sub(1)); + if !source_line.is_some_and(|line| task_source.is_match(line)) { + return captures[0].to_string(); + } + + let input = captures["input"].replacen( + " disabled=\"\"", + " data-task-checkbox=\"\" disabled=\"\"", + 1, + ); + format!( + "
  • {}", + &captures["sourcepos"], + input, + ) + }) + .into_owned() } #[tauri::command] @@ -818,6 +894,15 @@ async fn get_app_mode() -> String { } } +fn theme_slug(value: &str) -> String { + let lowercase = value.to_lowercase(); + lowercase + .split(|c: char| !c.is_alphanumeric()) + .filter(|segment| !segment.is_empty()) + .collect::>() + .join("-") +} + #[tauri::command] async fn fetch_vscode_theme(app: AppHandle, url: String) -> Result { use std::io::{Cursor, Read}; @@ -892,9 +977,7 @@ async fn fetch_vscode_theme(app: AppHandle, url: String) -> Result Some(tauri::window::Color(24, 24, 24, 255)), "light" => Some(tauri::window::Color(253, 253, 253, 255)), @@ -1467,9 +1548,7 @@ pub fn run() { let _ = window.set_background_color(bg_color); - let _ = _window.set_shadow(true); - - let window = app.get_webview_window(label).unwrap(); + let _ = window.set_shadow(true); let file_path = args.iter().skip(1).find(|arg| !arg.starts_with("-")); @@ -1569,12 +1648,12 @@ pub fn run() { .run(|_app_handle, _event| { #[cfg(target_os = "macos")] if let tauri::RunEvent::Opened { urls } = _event { - if let Some(url) = urls.first() { + for url in urls { if let Ok(path_buf) = url.to_file_path() { let path_str = path_buf.to_string_lossy().to_string(); let state = _app_handle.state::(); - *state.startup_file.lock().unwrap() = Some(path_str.clone()); + state.startup_files.lock().unwrap().push(path_str.clone()); if let Some(window) = pick_delivery_window(_app_handle) { let _ = _app_handle.emit_to(window.label(), "file-path", path_str); diff --git a/src-tauri/src/window_runtime.rs b/src-tauri/src/window_runtime.rs index a1a77709..41767b7d 100644 --- a/src-tauri/src/window_runtime.rs +++ b/src-tauri/src/window_runtime.rs @@ -21,7 +21,7 @@ impl WatcherState { } pub struct AppState { - pub(crate) startup_file: Mutex>, + pub(crate) startup_files: Mutex>, pub(crate) last_focused_viewer: Mutex>, window_registry: Mutex>, window_counter: AtomicU64, @@ -30,7 +30,7 @@ pub struct AppState { impl AppState { pub fn new() -> Self { Self { - startup_file: Mutex::new(None), + startup_files: Mutex::new(Vec::new()), last_focused_viewer: Mutex::new(None), window_registry: Mutex::new(HashMap::new()), window_counter: AtomicU64::new(0), @@ -288,10 +288,11 @@ pub fn watch_file( let mut watchers = state.watchers.lock().unwrap(); watchers.remove(&label); let event_label = label.clone(); + let watched_path = path.clone(); let mut watcher = RecommendedWatcher::new( move |result: Result| { if result.is_ok() { - let _ = handle.emit_to(event_label.as_str(), "file-changed", ()); + let _ = handle.emit_to(event_label.as_str(), "file-changed", watched_path.clone()); } }, Config::default(), @@ -314,7 +315,8 @@ pub fn send_markdown_path(state: State<'_, AppState>) -> Vec { .skip(1) .filter(|arg| !arg.starts_with('-')) .collect(); - if let Some(path) = state.startup_file.lock().unwrap().take() { + let startup_files: Vec = state.startup_files.lock().unwrap().drain(..).collect(); + for path in startup_files.into_iter().rev() { if !files.contains(&path) { files.insert(0, path); } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 3c9c6b8a..d416c61e 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -49,14 +49,6 @@ "name": "Markdown File", "description": "Opens Markdown files with Markpad", "role": "Editor" - }, - { - "ext": ["txt"], - "contentTypes": ["public.plain-text"], - "mimeType": "text/plain", - "name": "Text File", - "description": "Opens Text files with Markpad", - "role": "Editor" } ], "windows": { diff --git a/src/lib/MarkdownViewer.svelte b/src/lib/MarkdownViewer.svelte index d2044950..2060fee2 100644 --- a/src/lib/MarkdownViewer.svelte +++ b/src/lib/MarkdownViewer.svelte @@ -51,6 +51,7 @@ import { import HomePage from './components/HomePage.svelte'; import { tabManager } from './stores/tabs.svelte.js'; import { snapshotTab } from './utils/tabTransfer.js'; +import { getPreviewContentWidth } from './utils/previewWidth.js'; import { settings } from './stores/settings.svelte.js'; import { t } from './utils/i18n.js'; import { createWindowSession } from './sessions/windowSession.svelte.js'; @@ -223,7 +224,10 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu const TOC_MAX_WIDTH = 420; const TOC_RESIZE_STEP = 16; let isTocResizing = $state(false); - let isOverhanging = $derived(isFullWidth || (viewerWidth > 0 && settings.tocWidth > Math.max(50, (viewerWidth - 780) / 2))); + let previewContentWidth = $derived(getPreviewContentWidth(settings.previewMaxWidth, isFullWidth)); + let isOverhanging = $derived( + isFullWidth || (viewerWidth > 0 && previewContentWidth !== null && settings.tocWidth > Math.max(50, (viewerWidth - previewContentWidth) / 2)), + ); $effect(() => { localStorage.setItem('isFullWidth', String(isFullWidth)); @@ -525,7 +529,6 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu scrollFuture = []; }, renderMarkdown: renderMarkdownPreview, - isLiveMode: () => liveMode, afterLoad: tick, saveRecentFile, deleteRecentFile, @@ -620,6 +623,14 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu findOpen = false; }); + $effect(() => { + if (liveMode && currentFile) { + invoke('watch_file', { path: currentFile }).catch(console.error); + } else { + invoke('unwatch_file').catch(console.error); + } + }); + function processHighlights(root: Element) { const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { acceptNode(node) { @@ -1527,11 +1538,11 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu } async function toggleTaskCheckbox(checkbox: HTMLInputElement) { - const allBoxes = Array.from(markdownBody?.querySelectorAll('[data-task-checkbox]') || []); - const index = allBoxes.indexOf(checkbox); - if (index === -1) return; + const sourcePosition = checkbox.closest('li')?.getAttribute('data-sourcepos'); + const sourceLine = Number(sourcePosition?.match(/^(\d+):/)?.[1]); + if (!Number.isInteger(sourceLine) || sourceLine < 1) return; const nowChecked = !checkbox.checked; - if (!(await documentSession.toggleTaskCheckbox(index, nowChecked))) return; + if (!(await documentSession.toggleTaskCheckbox(sourceLine, nowChecked))) return; checkbox.checked = nowChecked; const li = checkbox.closest('li'); if (li) { @@ -1841,13 +1852,15 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu async function selectFile() { const selected = await open({ - multiple: false, + multiple: true, filters: [ { name: 'Markdown', extensions: ['md', 'markdown', 'mdown', 'mkd'] }, { name: 'All Files', extensions: ['*'] }, ], }); - if (selected && typeof selected === 'string') loadMarkdown(selected); + if (!selected) return; + const paths = Array.isArray(selected) ? selected : [selected]; + for (const path of paths) await loadMarkdown(path); } async function reloadFromDisk() { @@ -1907,14 +1920,8 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu if (currentFile) await invoke('open_file_folder', { path: currentFile }); } - async function toggleLiveMode() { + function toggleLiveMode() { liveMode = !liveMode; - if (liveMode && currentFile) { - await invoke('watch_file', { path: currentFile }); - if (tabManager.activeTabId) await loadMarkdown(currentFile); - } else { - await invoke('unwatch_file'); - } } async function saveImageAs(src: string) { @@ -2638,8 +2645,9 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu }), ); unlisteners.push( - await appWindow.listen('file-changed', () => { - if (!liveMode || !currentFile) return; + await appWindow.listen('file-changed', (event) => { + const changedPath = event.payload as string; + if (!liveMode || !currentFile || changedPath !== currentFile) return; // Skip events caused by our own auto-save / save invocations, // otherwise the reload would clobber any keystrokes that landed // between fs::write and this listener firing. @@ -2943,7 +2951,7 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu try { const args: string[] = await invoke('send_markdown_path'); if (!isDisposed && args?.length > 0) { - await loadMarkdown(args[0]); + for (const path of args) await loadMarkdown(path); } } catch (error) { console.error('Error receiving Markdown file path:', error); @@ -3157,7 +3165,7 @@ import { createDocumentSession, type LoadMarkdownOptions } from './sessions/docu if(e.key === 'Enter' || e.key === ' ') handleLinkClick(e as unknown as MouseEvent); }} tabindex="-1" - style="outline: none; font-family: {settings.previewFont}, sans-serif; font-size: {settings.previewFontSize}px; flex: 1;"> + style="outline: none; font-family: {settings.previewFont}, sans-serif; font-size: {settings.previewFontSize}px; flex: 1; --preview-max-width: {previewContentWidth === null ? '100%' : `${previewContentWidth}px`};"> {#if frontMatterInfo.exists}
    { - emitSync(); - }); - const d2 = editor.onDidScrollChange((e) => { + const scrollListener = editor.onDidScrollChange((e) => { if (e.scrollTopChanged) { emitSync(); } }); return () => { - d1.dispose(); - d2.dispose(); + scrollListener.dispose(); }; } }); diff --git a/src/lib/components/Settings.svelte b/src/lib/components/Settings.svelte index f1b8d7d6..dddfe64f 100644 --- a/src/lib/components/Settings.svelte +++ b/src/lib/components/Settings.svelte @@ -313,7 +313,8 @@ } function handleSettingsModalDragPointerDown(e: PointerEvent) { - if (e.button !== 0 || isSettingsHeaderInteractiveTarget(e.target)) return; + const header = e.target instanceof HTMLElement ? e.target.closest('.settings-header') : null; + if (e.button !== 0 || !header || !settingsModal?.contains(header) || isSettingsHeaderInteractiveTarget(e.target)) return; const frame = getCurrentSettingsModalFrame(); if (!frame) return; @@ -575,8 +576,9 @@ aria-modal="true" aria-labelledby="settings-title" tabindex="-1" + onpointerdown={handleSettingsModalDragPointerDown} onkeydown={handleModalKeydown}> -
    +

    {t('settings.title', settings.language)}

    -
    -
    -

    {t('settings.applicationToolbar', settings.language)}

    +
    + + + {t('settings.applicationToolbar', settings.language)} + +
    +
    {/each} +
    -
    - -
    -
    -

    {t('settings.editorToolbar', settings.language)}

    +
    + +
    + + + {t('settings.editorToolbar', settings.language)} + +
    +
    {/each} +
    - +
    {:else if activeCategory === 'files'}
    @@ -1712,10 +1724,21 @@ display: none; } - .toolbar-section { - display: flex; - flex-direction: column; - gap: 8px; + .toolbar-settings-chevron { + width: 7px; + height: 7px; + border-right: 1.5px solid var(--color-fg-muted); + border-bottom: 1.5px solid var(--color-fg-muted); + transform: rotate(-45deg); + transition: transform 0.12s ease; + } + + .toolbar-settings[open] .toolbar-settings-chevron { + transform: rotate(45deg); + } + + .toolbar-settings-body { + padding-bottom: 12px; } .toolbar-section-header { @@ -1725,15 +1748,6 @@ padding-bottom: 2px; } - .toolbar-section-header h3 { - margin: 0; - font-size: 12px; - font-weight: 600; - color: var(--color-fg-muted); - text-transform: uppercase; - letter-spacing: 0.5px; - } - .toolbar-settings-list { display: flex; flex-direction: column; diff --git a/src/lib/sessions/documentSession.svelte.ts b/src/lib/sessions/documentSession.svelte.ts index 4817f096..7c975d07 100644 --- a/src/lib/sessions/documentSession.svelte.ts +++ b/src/lib/sessions/documentSession.svelte.ts @@ -2,6 +2,7 @@ import { invoke } from '@tauri-apps/api/core'; import { save } from '@tauri-apps/plugin-dialog'; import { settings } from '../stores/settings.svelte.js'; import { tabManager } from '../stores/tabs.svelte.js'; +import { getMarkdownBodyWithoutFrontMatter } from '../utils/frontMatter.js'; import { hasMarkdownLinkExtension } from '../utils/markdownLinks.js'; export type LoadMarkdownOptions = { @@ -16,7 +17,6 @@ type DocumentSessionOptions = { currentFile: () => string; resetScrollHistory: () => void; renderMarkdown: (raw: string, path: string) => Promise; - isLiveMode: () => boolean; afterLoad: () => Promise; saveRecentFile: (path: string) => void; deleteRecentFile: (path: string) => void; @@ -137,16 +137,14 @@ export function createDocumentSession(options: DocumentSessionOptions) { if (tab) tab.isEditing = true; tabManager.setTabRawContent(activeId, content); } - if (options.isLiveMode()) invoke('watch_file', { path: filePath }).catch(console.error); await options.afterLoad(); if (filePath) options.saveRecentFile(filePath); } catch (error) { console.error('Error loading file:', error); - const errorText = String(error); - if (errorText.includes('The system cannot find the file specified') || errorText.includes('No such file or directory')) { - options.deleteRecentFile(filePath); - if (tabManager.activeTab?.path === filePath) tabManager.closeTab(tabManager.activeTab.id); - } else options.onError('Error loading file', error); + // A watcher can observe a transient gap while another process replaces + // the file. Keep the already-open buffer and recent-file entry instead + // of closing the tab and discarding the user's recovery path. + options.onError('Error loading file', error); } } @@ -212,15 +210,17 @@ export function createDocumentSession(options: DocumentSessionOptions) { } } - async function toggleTaskCheckbox(index: number, nowChecked: boolean) { + async function toggleTaskCheckbox(sourceLine: number, nowChecked: boolean) { const tab = tabManager.activeTab; if (!tab || !tab.path) return false; const raw = tab.rawContent; - let count = 0; - const updated = raw.replace(/^(\s*[-*+] )\[( |x|X)\]/gm, (match, prefix) => { - if (count++ === index) return `${prefix}[${nowChecked ? 'x' : ' '}]`; + const body = getMarkdownBodyWithoutFrontMatter(raw); + const updatedBody = body.replace(/^(\s*(?:>\s*)*(?:[-+*]|\d+[.)])\s+)\[( |x|X)\]/gm, (match, prefix, _state, offset) => { + const line = body.slice(0, offset).split('\n').length; + if (line === sourceLine) return `${prefix}[${nowChecked ? 'x' : ' '}]`; return match; }); + const updated = `${raw.slice(0, raw.length - body.length)}${updatedBody}`; if (updated === raw) return false; tabManager.updateTabRawContent(tab.id, updated); await saveContent(tab.id); diff --git a/src/lib/stores/settings.svelte.ts b/src/lib/stores/settings.svelte.ts index 30ca2f2d..1196ee3b 100644 --- a/src/lib/stores/settings.svelte.ts +++ b/src/lib/stores/settings.svelte.ts @@ -18,6 +18,10 @@ import { normalizeTitlebarToolbarPlacement, type TitlebarToolbarPlacement, } from '../utils/titlebarToolbar.js'; +import { + DEFAULT_PREVIEW_MAX_WIDTH, + normalizePreviewMaxWidth, +} from '../utils/previewWidth.js'; export type OSType = 'macos' | 'windows' | 'linux' | 'unknown'; export type LanguageCode = @@ -169,6 +173,7 @@ export class SettingsStore { newFileDefaultMode = $state(true); showRecentFiles = $state(true); editorMaxWidth = $state(80); + previewMaxWidth = $state(DEFAULT_PREVIEW_MAX_WIDTH); pinnedToc = $state(false); tocSide = $state<'left' | 'right'>('left'); tocWidth = $state(240); @@ -218,6 +223,7 @@ export class SettingsStore { const savedNewFileDefaultMode = localStorage.getItem('editor.newFileDefaultMode'); const savedShowRecentFiles = localStorage.getItem('editor.showRecentFiles'); const savedEditorMaxWidth = localStorage.getItem('editor.maxWidth'); + const savedPreviewMaxWidth = localStorage.getItem('preview.maxWidth'); const savedPinnedToc = localStorage.getItem('editor.pinnedToc'); const savedTocSide = localStorage.getItem('editor.tocSide'); const savedTocWidth = localStorage.getItem('editor.tocWidth'); @@ -287,6 +293,7 @@ export class SettingsStore { if (savedNewFileDefaultMode !== null) this.newFileDefaultMode = savedNewFileDefaultMode === 'true'; if (savedShowRecentFiles !== null) this.showRecentFiles = savedShowRecentFiles === 'true'; if (savedEditorMaxWidth !== null) this.editorMaxWidth = parseFontSize(savedEditorMaxWidth, 80, 20, 500); + this.previewMaxWidth = normalizePreviewMaxWidth(savedPreviewMaxWidth); if (savedPinnedToc !== null) this.pinnedToc = savedPinnedToc === 'true'; if (savedTocSide !== null) this.tocSide = savedTocSide as 'left' | 'right'; if (savedTocWidth !== null) this.tocWidth = parseFontSize(savedTocWidth, 240, 180, 420); @@ -361,6 +368,7 @@ export class SettingsStore { localStorage.setItem('editor.newFileDefaultMode', String(this.newFileDefaultMode)); localStorage.setItem('editor.showRecentFiles', String(this.showRecentFiles)); localStorage.setItem('editor.maxWidth', String(this.editorMaxWidth)); + localStorage.setItem('preview.maxWidth', String(this.previewMaxWidth)); localStorage.setItem('editor.pinnedToc', String(this.pinnedToc)); localStorage.setItem('editor.tocSide', this.tocSide); localStorage.setItem('editor.tocWidth', String(this.tocWidth)); @@ -583,6 +591,10 @@ export class SettingsStore { this.editorMaxWidth = 80; } + resetPreviewMaxWidth() { + this.previewMaxWidth = DEFAULT_PREVIEW_MAX_WIDTH; + } + async initOSType() { try { const osType = await invoke('get_os_type'); diff --git a/src/lib/utils/markdown.ts b/src/lib/utils/markdown.ts index d1a040b3..e8f5e9ef 100644 --- a/src/lib/utils/markdown.ts +++ b/src/lib/utils/markdown.ts @@ -361,43 +361,16 @@ function stripLeadingWhitespace(nodes: Node[]) { } } -function isWhitespaceText(node: Node) { - return node.nodeType === 3 && !node.textContent?.trim(); -} - -function startsWithNode(element: Element, target: Node) { - const firstContentNode = Array.from(element.childNodes).find( - (node) => !isWhitespaceText(node), - ); - return firstContentNode === target; -} - -function isTaskCheckbox(input: Element, li: Element) { - const looksRenderedByTaskList = - input.hasAttribute("data-task-checkbox") || - li.classList.contains("task-list-item"); - if (!looksRenderedByTaskList) return false; - - const inputParent = input.parentElement; - if (inputParent === li) { - return startsWithNode(li, input); - } - - return ( - inputParent?.tagName === "P" && - inputParent.parentElement === li && - startsWithNode(li, inputParent) && - startsWithNode(inputParent, input) - ); -} - function processTaskItems(root: Element) { for (const input of Array.from( root.querySelectorAll('li input[type="checkbox"]'), )) { const li = input.closest("li"); if (!li) continue; - if (!isTaskCheckbox(input, li)) continue; + if (!input.hasAttribute("data-task-checkbox")) { + input.setAttribute("disabled", ""); + continue; + } input.setAttribute("data-task-checkbox", ""); input.removeAttribute("disabled"); diff --git a/src/lib/utils/previewWidth.ts b/src/lib/utils/previewWidth.ts new file mode 100644 index 00000000..9184cbd1 --- /dev/null +++ b/src/lib/utils/previewWidth.ts @@ -0,0 +1,14 @@ +export const MIN_PREVIEW_MAX_WIDTH = 640; +export const MAX_PREVIEW_MAX_WIDTH = 1600; +export const DEFAULT_PREVIEW_MAX_WIDTH = 880; + +export function normalizePreviewMaxWidth(value: unknown): number { + if (value === null || value === '') return DEFAULT_PREVIEW_MAX_WIDTH; + const parsed = typeof value === 'number' ? value : Number(value); + if (!Number.isFinite(parsed)) return DEFAULT_PREVIEW_MAX_WIDTH; + return Math.min(MAX_PREVIEW_MAX_WIDTH, Math.max(MIN_PREVIEW_MAX_WIDTH, Math.round(parsed))); +} + +export function getPreviewContentWidth(value: unknown, isFullWidth: boolean): number | null { + return isFullWidth ? null : normalizePreviewMaxWidth(value); +}