fix(workspace): stream incremental markdown rendering
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
"dev": "deno run -A npm:vite@7.2.7 dev",
|
||||
"dev:backend": "cd ../.. && cargo run -p yoi-workspace-server --bin yoi-server -- serve --listen 127.0.0.1:8787",
|
||||
"check": "deno run -A npm:@sveltejs/kit@2.49.4 sync && deno run -A npm:svelte-check@4.3.4 --tsconfig ./tsconfig.json",
|
||||
"test": "deno test --allow-read=src,test,tests --allow-env=LOG,VSCODE_TEXTMATE_DEBUG,NODE_ENV tests/workspace-model.test.ts tests/workspace-catalog.test.ts tests/profile-api.test.ts tests/skill-api.test.ts src/lib/workspace/auth/model.test.ts tests/auth-api.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/api/workers.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts src/lib/workspace/console/composer-delivery.test.ts test/composer-history.test.ts tests/composer-paste.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-draft.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/markdown.test.ts test/console/ansi.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/console/run-status.test.ts src/lib/workspace/companion/api.test.ts tests/workdir-api.test.ts src/lib/workspace/console/tasks.test.ts test/ticket-detail-route-reuse.test.ts test/objective-pages.test.ts test/repositories/ui.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts tests/runtime-connection.test.ts tests/runtime-management.test.ts tests/runtime-management-source.test.ts src/lib/workspace/sidebar/override-stack.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/workspace-switcher.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-launch.test.ts test/sidebar/worker-actions.test.ts src/lib/workspace/tickets/merge-request-resources.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/merge-request-status.test.ts test/config-source/decodal-grammar.test.ts test/config-source/editor-state.test.ts test/config-source/fixed-schema-wrapper.test.ts test/config-source/toolchain.test.ts test/config-source/wasm-parity.test.ts test/repository-access/api.test.ts test/repository-access/loader.test.ts test/repository-access/ui.test.ts test/repository-ssh-connection-ui.test.ts",
|
||||
"test": "deno test --allow-read=src,test,tests --allow-env=LOG,VSCODE_TEXTMATE_DEBUG,NODE_ENV tests/workspace-model.test.ts tests/workspace-catalog.test.ts tests/profile-api.test.ts tests/skill-api.test.ts src/lib/workspace/auth/model.test.ts tests/auth-api.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/api/workers.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts src/lib/workspace/console/composer-delivery.test.ts test/composer-history.test.ts tests/composer-paste.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-draft.test.ts src/lib/workspace/console/composer-completion.test.ts test/console/ansi.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/console/run-status.test.ts src/lib/workspace/companion/api.test.ts tests/workdir-api.test.ts src/lib/workspace/console/tasks.test.ts test/ticket-detail-route-reuse.test.ts test/objective-pages.test.ts test/repositories/ui.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts tests/runtime-connection.test.ts tests/runtime-management.test.ts tests/runtime-management-source.test.ts src/lib/workspace/sidebar/override-stack.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/workspace-switcher.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-launch.test.ts test/sidebar/worker-actions.test.ts src/lib/workspace/tickets/merge-request-resources.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/merge-request-status.test.ts test/config-source/decodal-grammar.test.ts test/config-source/editor-state.test.ts test/config-source/fixed-schema-wrapper.test.ts test/config-source/toolchain.test.ts test/config-source/wasm-parity.test.ts test/repository-access/api.test.ts test/repository-access/loader.test.ts test/repository-access/ui.test.ts test/repository-ssh-connection-ui.test.ts",
|
||||
"test:component": "deno run -A npm:vitest@3.2.4 run --config vitest.config.ts",
|
||||
"build": "deno run -A npm:vite@7.2.7 build",
|
||||
"preview": "deno run -A npm:vite@7.2.7 preview"
|
||||
},
|
||||
@@ -27,7 +28,7 @@
|
||||
"cookie": "npm:cookie@0.6.0",
|
||||
"devalue": "npm:devalue@5.6.4",
|
||||
"set-cookie-parser": "npm:set-cookie-parser@2.7.2",
|
||||
"shiki": "npm:shiki@3.13.0",
|
||||
"shiki": "npm:shiki@4.4.2",
|
||||
"svelte": "npm:svelte@5.45.6",
|
||||
"svelte-check": "npm:svelte-check@4.3.4",
|
||||
"typescript": "npm:typescript@5.9.3",
|
||||
|
||||
Generated
+397
-23
@@ -9,23 +9,27 @@
|
||||
"npm:@codemirror/state@6.7.1": "6.7.1",
|
||||
"npm:@codemirror/view@6.43.8": "6.43.8",
|
||||
"npm:@fontsource/ibm-plex-mono@5.3.0": "5.3.0",
|
||||
"npm:@humanspeak/svelte-markdown@1.9.1": "1.9.1_shiki@4.4.2_svelte@5.45.6",
|
||||
"npm:@lezer/common@1.5.2": "1.5.2",
|
||||
"npm:@lezer/highlight@1.2.3": "1.2.3",
|
||||
"npm:@sveltejs/adapter-static@3.0.9": "3.0.9_@sveltejs+kit@2.49.4__@sveltejs+vite-plugin-svelte@6.2.1___svelte@5.45.6___vite@7.2.7____yaml@2.9.0___yaml@2.9.0__svelte@5.45.6__typescript@5.9.3__vite@7.2.7___yaml@2.9.0__yaml@2.9.0_yaml@2.9.0",
|
||||
"npm:@sveltejs/kit@2.49.4": "2.49.4_@sveltejs+vite-plugin-svelte@6.2.1__svelte@5.45.6__vite@7.2.7___yaml@2.9.0__yaml@2.9.0_svelte@5.45.6_typescript@5.9.3_vite@7.2.7__yaml@2.9.0_yaml@2.9.0",
|
||||
"npm:@sveltejs/vite-plugin-svelte@6.2.1": "6.2.1_svelte@5.45.6_vite@7.2.7__yaml@2.9.0_yaml@2.9.0",
|
||||
"npm:@testing-library/svelte@5.2.8": "5.2.8_svelte@5.45.6_vite@7.2.7__yaml@2.9.0_vitest@3.2.4__happy-dom@18.0.1_happy-dom@18.0.1",
|
||||
"npm:clsx@2.1.1": "2.1.1",
|
||||
"npm:cookie@0.6.0": "0.6.0",
|
||||
"npm:decodal-codemirror@0.3.0": "0.3.0_@codemirror+language@6.12.4_@codemirror+view@6.43.8_@lezer+highlight@1.2.3_@lezer+lr@1.4.10",
|
||||
"npm:devalue@5.6.4": "5.6.4",
|
||||
"npm:gen-interface-jp@0.8.0": "0.8.0",
|
||||
"npm:happy-dom@18.0.1": "18.0.1",
|
||||
"npm:set-cookie-parser@2.7.2": "2.7.2",
|
||||
"npm:shiki@3.13.0": "3.13.0",
|
||||
"npm:shiki@4.4.2": "4.4.2",
|
||||
"npm:sv@*": "0.10.8",
|
||||
"npm:svelte-check@4.3.4": "4.3.4_svelte@5.45.6_typescript@5.9.3",
|
||||
"npm:svelte@5.45.6": "5.45.6",
|
||||
"npm:typescript@5.9.3": "5.9.3",
|
||||
"npm:vite@7.2.7": "7.2.7_yaml@2.9.0",
|
||||
"npm:vitest@3.2.4": "3.2.4_happy-dom@18.0.1",
|
||||
"npm:yaml@2.9.0": "2.9.0"
|
||||
},
|
||||
"jsr": {
|
||||
@@ -40,6 +44,20 @@
|
||||
}
|
||||
},
|
||||
"npm": {
|
||||
"@babel/code-frame@7.29.7": {
|
||||
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
|
||||
"dependencies": [
|
||||
"@babel/helper-validator-identifier",
|
||||
"js-tokens@4.0.0",
|
||||
"picocolors"
|
||||
]
|
||||
},
|
||||
"@babel/helper-validator-identifier@7.29.7": {
|
||||
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="
|
||||
},
|
||||
"@babel/runtime@7.29.7": {
|
||||
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="
|
||||
},
|
||||
"@codemirror/autocomplete@6.20.0": {
|
||||
"integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==",
|
||||
"dependencies": [
|
||||
@@ -217,6 +235,23 @@
|
||||
"@fontsource/ibm-plex-mono@5.3.0": {
|
||||
"integrity": "sha512-eTgnZjZEGk1QtD3ZstF+Vclo2HLAni8YMy34/DxllwZvyz1lR/1RF/xTiAquOBO7MvqBx8D2Ig2WCPMVfdZu7Q=="
|
||||
},
|
||||
"@humanspeak/memory-cache@1.2.0": {
|
||||
"integrity": "sha512-im7GIIpgjdD6Fx68xCeiXw3XiDv30/WMRAaodMm+ep0ptYfEUd0cdNeTAylHGIRTJIeByKFHdTmPjAktyDM/JQ=="
|
||||
},
|
||||
"@humanspeak/svelte-markdown@1.9.1_shiki@4.4.2_svelte@5.45.6": {
|
||||
"integrity": "sha512-2JjpATdZfhGQurV38LtkUkPkyQzM7eXku6LoDBeK6i69qqOe0OLmMwpqtMnhwG3ItdxXOt/3miPbSaNTFqMl5Q==",
|
||||
"dependencies": [
|
||||
"@humanspeak/memory-cache",
|
||||
"github-slugger",
|
||||
"htmlparser2",
|
||||
"marked",
|
||||
"shiki",
|
||||
"svelte"
|
||||
],
|
||||
"optionalPeers": [
|
||||
"shiki"
|
||||
]
|
||||
},
|
||||
"@jridgewell/gen-mapping@0.3.13": {
|
||||
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
||||
"dependencies": [
|
||||
@@ -390,44 +425,53 @@
|
||||
"os": ["win32"],
|
||||
"cpu": ["x64"]
|
||||
},
|
||||
"@shikijs/core@3.13.0": {
|
||||
"integrity": "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA==",
|
||||
"@shikijs/core@4.4.2": {
|
||||
"integrity": "sha512-StyzbAyxg2/tBGf78gwbBkGyeQ73lf8UiJArFaQhTQIDqQOCKPCQFanvrs4/Yv3Yfyc+ONInJM6K+FMIf+P+kA==",
|
||||
"dependencies": [
|
||||
"@shikijs/primitive",
|
||||
"@shikijs/types",
|
||||
"@shikijs/vscode-textmate",
|
||||
"@types/hast",
|
||||
"hast-util-to-html"
|
||||
]
|
||||
},
|
||||
"@shikijs/engine-javascript@3.13.0": {
|
||||
"integrity": "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg==",
|
||||
"@shikijs/engine-javascript@4.4.2": {
|
||||
"integrity": "sha512-MnIkeqWdVPUWsxlx8gKLVCJFTsqrQJgpTPBPpQwaFeJ56lOnJxj5aN2LUFnfxUEcvOQuNocmbaMnVrCEln6rkw==",
|
||||
"dependencies": [
|
||||
"@shikijs/types",
|
||||
"@shikijs/vscode-textmate",
|
||||
"oniguruma-to-es"
|
||||
]
|
||||
},
|
||||
"@shikijs/engine-oniguruma@3.13.0": {
|
||||
"integrity": "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg==",
|
||||
"@shikijs/engine-oniguruma@4.4.2": {
|
||||
"integrity": "sha512-GLhowz1+jixjz+wiZ3wMnOn1jTxiFCGl2PkXufivbnwPHKuyw1AYqu5/hbWhZZ2oAb0NP05WUJhYeigY14drnw==",
|
||||
"dependencies": [
|
||||
"@shikijs/types",
|
||||
"@shikijs/vscode-textmate"
|
||||
]
|
||||
},
|
||||
"@shikijs/langs@3.13.0": {
|
||||
"integrity": "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ==",
|
||||
"@shikijs/langs@4.4.2": {
|
||||
"integrity": "sha512-8DfeusD+Zdv/eYIDdXyJTUnSMHt+aAWjAOCXV20HNGAHRlInXpG8wh421v6B91WOm9TFwRLN+b/LG5F2NAIojg==",
|
||||
"dependencies": [
|
||||
"@shikijs/types"
|
||||
]
|
||||
},
|
||||
"@shikijs/themes@3.13.0": {
|
||||
"integrity": "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg==",
|
||||
"@shikijs/primitive@4.4.2": {
|
||||
"integrity": "sha512-l6fQQKsOMlz72n38fztmSgZ76MO6KSWuw8o+GJ+FhmqrpC9pIOJNQNXGgbb5yX2AwpzlEHwsaLPnk/8o4Fm+rA==",
|
||||
"dependencies": [
|
||||
"@shikijs/types",
|
||||
"@shikijs/vscode-textmate",
|
||||
"@types/hast"
|
||||
]
|
||||
},
|
||||
"@shikijs/themes@4.4.2": {
|
||||
"integrity": "sha512-H0CFoL07ddDC2Dd6EdrPYNkRhUR6YCkJlnuYFceYYUJJA5TIm2b5B33qqiDYryBExgbKMndFJPb2u1gTuqO37g==",
|
||||
"dependencies": [
|
||||
"@shikijs/types"
|
||||
]
|
||||
},
|
||||
"@shikijs/types@3.13.0": {
|
||||
"integrity": "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw==",
|
||||
"@shikijs/types@4.4.2": {
|
||||
"integrity": "sha512-PFYitV4vpDr/iPCIhnHp+Q4ftic5N5VeNJ3KQ1O8gn3h2ar8qgwMAXF7tq4m1CWaMS60fV4VqF6vfnWH4F7vqQ==",
|
||||
"dependencies": [
|
||||
"@shikijs/vscode-textmate",
|
||||
"@types/hast"
|
||||
@@ -498,14 +542,53 @@
|
||||
"vitefu"
|
||||
]
|
||||
},
|
||||
"@testing-library/dom@10.4.2": {
|
||||
"integrity": "sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q==",
|
||||
"dependencies": [
|
||||
"@babel/code-frame",
|
||||
"@babel/runtime",
|
||||
"@types/aria-query",
|
||||
"aria-query@5.3.0",
|
||||
"dom-accessibility-api",
|
||||
"lz-string",
|
||||
"picocolors",
|
||||
"pretty-format"
|
||||
]
|
||||
},
|
||||
"@testing-library/svelte@5.2.8_svelte@5.45.6_vite@7.2.7__yaml@2.9.0_vitest@3.2.4__happy-dom@18.0.1_happy-dom@18.0.1": {
|
||||
"integrity": "sha512-ucQOtGsJhtawOEtUmbR4rRh53e6RbM1KUluJIXRmh6D4UzxR847iIqqjRtg9mHNFmGQ8Vkam9yVcR5d1mhIHKA==",
|
||||
"dependencies": [
|
||||
"@testing-library/dom",
|
||||
"svelte",
|
||||
"vite",
|
||||
"vitest"
|
||||
],
|
||||
"optionalPeers": [
|
||||
"vite",
|
||||
"vitest"
|
||||
]
|
||||
},
|
||||
"@types/aria-query@5.0.4": {
|
||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="
|
||||
},
|
||||
"@types/chai@5.2.3": {
|
||||
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
|
||||
"dependencies": [
|
||||
"@types/deep-eql",
|
||||
"assertion-error"
|
||||
]
|
||||
},
|
||||
"@types/cookie@0.6.0": {
|
||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
||||
},
|
||||
"@types/deep-eql@4.0.2": {
|
||||
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="
|
||||
},
|
||||
"@types/estree@1.0.8": {
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="
|
||||
},
|
||||
"@types/hast@3.0.4": {
|
||||
"integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
|
||||
"@types/hast@3.0.5": {
|
||||
"integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==",
|
||||
"dependencies": [
|
||||
"@types/unist"
|
||||
]
|
||||
@@ -516,9 +599,18 @@
|
||||
"@types/unist"
|
||||
]
|
||||
},
|
||||
"@types/node@20.19.43": {
|
||||
"integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
|
||||
"dependencies": [
|
||||
"undici-types"
|
||||
]
|
||||
},
|
||||
"@types/unist@3.0.3": {
|
||||
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="
|
||||
},
|
||||
"@types/whatwg-mimetype@3.0.2": {
|
||||
"integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="
|
||||
},
|
||||
"@typescript-eslint/types@8.57.2": {
|
||||
"integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA=="
|
||||
},
|
||||
@@ -526,25 +618,114 @@
|
||||
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
|
||||
"deprecated": true
|
||||
},
|
||||
"@vitest/expect@3.2.4": {
|
||||
"integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
|
||||
"dependencies": [
|
||||
"@types/chai",
|
||||
"@vitest/spy",
|
||||
"@vitest/utils",
|
||||
"chai",
|
||||
"tinyrainbow"
|
||||
]
|
||||
},
|
||||
"@vitest/mocker@3.2.4_vite@7.2.7__yaml@2.9.0": {
|
||||
"integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
|
||||
"dependencies": [
|
||||
"@vitest/spy",
|
||||
"estree-walker",
|
||||
"magic-string",
|
||||
"vite"
|
||||
],
|
||||
"optionalPeers": [
|
||||
"vite"
|
||||
]
|
||||
},
|
||||
"@vitest/pretty-format@3.2.4": {
|
||||
"integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
|
||||
"dependencies": [
|
||||
"tinyrainbow"
|
||||
]
|
||||
},
|
||||
"@vitest/runner@3.2.4": {
|
||||
"integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
|
||||
"dependencies": [
|
||||
"@vitest/utils",
|
||||
"pathe",
|
||||
"strip-literal"
|
||||
]
|
||||
},
|
||||
"@vitest/snapshot@3.2.4": {
|
||||
"integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
|
||||
"dependencies": [
|
||||
"@vitest/pretty-format",
|
||||
"magic-string",
|
||||
"pathe"
|
||||
]
|
||||
},
|
||||
"@vitest/spy@3.2.4": {
|
||||
"integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
|
||||
"dependencies": [
|
||||
"tinyspy"
|
||||
]
|
||||
},
|
||||
"@vitest/utils@3.2.4": {
|
||||
"integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
|
||||
"dependencies": [
|
||||
"@vitest/pretty-format",
|
||||
"loupe",
|
||||
"tinyrainbow"
|
||||
]
|
||||
},
|
||||
"acorn@8.16.0": {
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||
"bin": true
|
||||
},
|
||||
"ansi-regex@5.0.1": {
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||
},
|
||||
"ansi-styles@5.2.0": {
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
|
||||
},
|
||||
"aria-query@5.3.0": {
|
||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||
"dependencies": [
|
||||
"dequal"
|
||||
]
|
||||
},
|
||||
"aria-query@5.3.2": {
|
||||
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="
|
||||
},
|
||||
"assertion-error@2.0.1": {
|
||||
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="
|
||||
},
|
||||
"axobject-query@4.1.0": {
|
||||
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="
|
||||
},
|
||||
"cac@6.7.14": {
|
||||
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="
|
||||
},
|
||||
"ccount@2.0.1": {
|
||||
"integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="
|
||||
},
|
||||
"chai@5.3.3": {
|
||||
"integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
|
||||
"dependencies": [
|
||||
"assertion-error",
|
||||
"check-error",
|
||||
"deep-eql",
|
||||
"loupe",
|
||||
"pathval"
|
||||
]
|
||||
},
|
||||
"character-entities-html4@2.1.0": {
|
||||
"integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="
|
||||
},
|
||||
"character-entities-legacy@3.0.0": {
|
||||
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="
|
||||
},
|
||||
"check-error@2.1.3": {
|
||||
"integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="
|
||||
},
|
||||
"chokidar@4.0.3": {
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dependencies": [
|
||||
@@ -578,6 +759,9 @@
|
||||
"@lezer/lr"
|
||||
]
|
||||
},
|
||||
"deep-eql@5.0.2": {
|
||||
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="
|
||||
},
|
||||
"deepmerge@4.3.1": {
|
||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="
|
||||
},
|
||||
@@ -593,6 +777,40 @@
|
||||
"dequal"
|
||||
]
|
||||
},
|
||||
"dom-accessibility-api@0.5.16": {
|
||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="
|
||||
},
|
||||
"dom-serializer@3.1.1": {
|
||||
"integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==",
|
||||
"dependencies": [
|
||||
"domelementtype",
|
||||
"domhandler",
|
||||
"entities"
|
||||
]
|
||||
},
|
||||
"domelementtype@3.0.0": {
|
||||
"integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="
|
||||
},
|
||||
"domhandler@6.0.1": {
|
||||
"integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==",
|
||||
"dependencies": [
|
||||
"domelementtype"
|
||||
]
|
||||
},
|
||||
"domutils@4.0.2": {
|
||||
"integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==",
|
||||
"dependencies": [
|
||||
"dom-serializer",
|
||||
"domelementtype",
|
||||
"domhandler"
|
||||
]
|
||||
},
|
||||
"entities@8.1.0": {
|
||||
"integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA=="
|
||||
},
|
||||
"es-module-lexer@1.7.0": {
|
||||
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="
|
||||
},
|
||||
"esbuild@0.25.12": {
|
||||
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
||||
"optionalDependencies": [
|
||||
@@ -636,6 +854,15 @@
|
||||
"@typescript-eslint/types"
|
||||
]
|
||||
},
|
||||
"estree-walker@3.0.3": {
|
||||
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
||||
"dependencies": [
|
||||
"@types/estree"
|
||||
]
|
||||
},
|
||||
"expect-type@1.4.0": {
|
||||
"integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA=="
|
||||
},
|
||||
"fdir@6.5.0_picomatch@4.0.4": {
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dependencies": [
|
||||
@@ -653,6 +880,17 @@
|
||||
"gen-interface-jp@0.8.0": {
|
||||
"integrity": "sha512-7rIytSAfuugVjYithrQseT0zqeUIkJd0LY3Ugdfbk/FxzMSeagcskeZlof5uWJ5liW3Zhn7pdLHq2OIvAftx+A=="
|
||||
},
|
||||
"github-slugger@2.0.0": {
|
||||
"integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="
|
||||
},
|
||||
"happy-dom@18.0.1": {
|
||||
"integrity": "sha512-qn+rKOW7KWpVTtgIUi6RVmTBZJSe2k0Db0vh1f7CWrWclkkc7/Q+FrOfkZIb2eiErLyqu5AXEzE7XthO9JVxRA==",
|
||||
"dependencies": [
|
||||
"@types/node",
|
||||
"@types/whatwg-mimetype",
|
||||
"whatwg-mimetype"
|
||||
]
|
||||
},
|
||||
"hast-util-to-html@9.0.5": {
|
||||
"integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==",
|
||||
"dependencies": [
|
||||
@@ -678,24 +916,50 @@
|
||||
"html-void-elements@3.0.0": {
|
||||
"integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="
|
||||
},
|
||||
"htmlparser2@12.0.0": {
|
||||
"integrity": "sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==",
|
||||
"dependencies": [
|
||||
"domelementtype",
|
||||
"domhandler",
|
||||
"domutils",
|
||||
"entities"
|
||||
]
|
||||
},
|
||||
"is-reference@3.0.3": {
|
||||
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
|
||||
"dependencies": [
|
||||
"@types/estree"
|
||||
]
|
||||
},
|
||||
"js-tokens@4.0.0": {
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"js-tokens@9.0.1": {
|
||||
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="
|
||||
},
|
||||
"kleur@4.1.5": {
|
||||
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="
|
||||
},
|
||||
"locate-character@3.0.0": {
|
||||
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="
|
||||
},
|
||||
"loupe@3.2.1": {
|
||||
"integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="
|
||||
},
|
||||
"lz-string@1.5.0": {
|
||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||
"bin": true
|
||||
},
|
||||
"magic-string@0.30.21": {
|
||||
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
||||
"dependencies": [
|
||||
"@jridgewell/sourcemap-codec"
|
||||
]
|
||||
},
|
||||
"marked@18.0.13": {
|
||||
"integrity": "sha512-xTxVzZsBFwunP6HDmtBkabUQEYArnP7/rMDGmPj9SlrKlQ4i8MdYVow+nJL0eOqwpUqhzBoTBRADGN6uYwPyOw==",
|
||||
"bin": true
|
||||
},
|
||||
"mdast-util-to-hast@13.2.1": {
|
||||
"integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
|
||||
"dependencies": [
|
||||
@@ -750,17 +1014,23 @@
|
||||
"obug@2.1.1": {
|
||||
"integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="
|
||||
},
|
||||
"oniguruma-parser@0.12.1": {
|
||||
"integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="
|
||||
"oniguruma-parser@0.12.2": {
|
||||
"integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="
|
||||
},
|
||||
"oniguruma-to-es@4.3.4": {
|
||||
"integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==",
|
||||
"oniguruma-to-es@4.3.6": {
|
||||
"integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==",
|
||||
"dependencies": [
|
||||
"oniguruma-parser",
|
||||
"regex",
|
||||
"regex-recursion"
|
||||
]
|
||||
},
|
||||
"pathe@2.0.3": {
|
||||
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="
|
||||
},
|
||||
"pathval@2.0.1": {
|
||||
"integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="
|
||||
},
|
||||
"picocolors@1.1.1": {
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
|
||||
},
|
||||
@@ -775,9 +1045,20 @@
|
||||
"source-map-js"
|
||||
]
|
||||
},
|
||||
"pretty-format@27.5.1": {
|
||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||
"dependencies": [
|
||||
"ansi-regex",
|
||||
"ansi-styles",
|
||||
"react-is"
|
||||
]
|
||||
},
|
||||
"property-information@7.1.0": {
|
||||
"integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="
|
||||
},
|
||||
"react-is@17.0.2": {
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||
},
|
||||
"readdirp@4.1.2": {
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="
|
||||
},
|
||||
@@ -840,8 +1121,8 @@
|
||||
"set-cookie-parser@2.7.2": {
|
||||
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="
|
||||
},
|
||||
"shiki@3.13.0": {
|
||||
"integrity": "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g==",
|
||||
"shiki@4.4.2": {
|
||||
"integrity": "sha512-P8F/dFhRevaw2uSdeIYlq/5SXZNY85DPtmXQ947gD1Zj2JqO5AkNvVVBar0Me9JkFx3uzVud/qOtP5ek9NEQGA==",
|
||||
"dependencies": [
|
||||
"@shikijs/core",
|
||||
"@shikijs/engine-javascript",
|
||||
@@ -853,6 +1134,9 @@
|
||||
"@types/hast"
|
||||
]
|
||||
},
|
||||
"siginfo@2.0.0": {
|
||||
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="
|
||||
},
|
||||
"sirv@3.0.2": {
|
||||
"integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
|
||||
"dependencies": [
|
||||
@@ -867,6 +1151,12 @@
|
||||
"space-separated-tokens@2.0.2": {
|
||||
"integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="
|
||||
},
|
||||
"stackback@0.0.2": {
|
||||
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="
|
||||
},
|
||||
"std-env@3.10.0": {
|
||||
"integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="
|
||||
},
|
||||
"stringify-entities@4.0.4": {
|
||||
"integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
|
||||
"dependencies": [
|
||||
@@ -874,6 +1164,12 @@
|
||||
"character-entities-legacy"
|
||||
]
|
||||
},
|
||||
"strip-literal@3.1.0": {
|
||||
"integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
|
||||
"dependencies": [
|
||||
"js-tokens@9.0.1"
|
||||
]
|
||||
},
|
||||
"style-mod@4.1.3": {
|
||||
"integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="
|
||||
},
|
||||
@@ -902,7 +1198,7 @@
|
||||
"@sveltejs/acorn-typescript",
|
||||
"@types/estree",
|
||||
"acorn",
|
||||
"aria-query",
|
||||
"aria-query@5.3.2",
|
||||
"axobject-query",
|
||||
"clsx",
|
||||
"devalue",
|
||||
@@ -914,6 +1210,12 @@
|
||||
"zimmerframe"
|
||||
]
|
||||
},
|
||||
"tinybench@2.9.0": {
|
||||
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="
|
||||
},
|
||||
"tinyexec@0.3.2": {
|
||||
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="
|
||||
},
|
||||
"tinyglobby@0.2.15": {
|
||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||
"dependencies": [
|
||||
@@ -921,6 +1223,15 @@
|
||||
"picomatch"
|
||||
]
|
||||
},
|
||||
"tinypool@1.1.1": {
|
||||
"integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="
|
||||
},
|
||||
"tinyrainbow@2.0.0": {
|
||||
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="
|
||||
},
|
||||
"tinyspy@4.0.6": {
|
||||
"integrity": "sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg=="
|
||||
},
|
||||
"totalist@3.0.1": {
|
||||
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="
|
||||
},
|
||||
@@ -931,6 +1242,9 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"bin": true
|
||||
},
|
||||
"undici-types@6.21.0": {
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="
|
||||
},
|
||||
"unist-util-is@6.0.1": {
|
||||
"integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==",
|
||||
"dependencies": [
|
||||
@@ -978,6 +1292,17 @@
|
||||
"vfile-message"
|
||||
]
|
||||
},
|
||||
"vite-node@3.2.4": {
|
||||
"integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
|
||||
"dependencies": [
|
||||
"cac",
|
||||
"debug",
|
||||
"es-module-lexer",
|
||||
"pathe",
|
||||
"vite"
|
||||
],
|
||||
"bin": true
|
||||
},
|
||||
"vite@7.2.7_yaml@2.9.0": {
|
||||
"integrity": "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==",
|
||||
"dependencies": [
|
||||
@@ -1006,9 +1331,53 @@
|
||||
"vite"
|
||||
]
|
||||
},
|
||||
"vitest@3.2.4_happy-dom@18.0.1": {
|
||||
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
||||
"dependencies": [
|
||||
"@types/chai",
|
||||
"@vitest/expect",
|
||||
"@vitest/mocker",
|
||||
"@vitest/pretty-format",
|
||||
"@vitest/runner",
|
||||
"@vitest/snapshot",
|
||||
"@vitest/spy",
|
||||
"@vitest/utils",
|
||||
"chai",
|
||||
"debug",
|
||||
"expect-type",
|
||||
"happy-dom",
|
||||
"magic-string",
|
||||
"pathe",
|
||||
"picomatch",
|
||||
"std-env",
|
||||
"tinybench",
|
||||
"tinyexec",
|
||||
"tinyglobby",
|
||||
"tinypool",
|
||||
"tinyrainbow",
|
||||
"vite",
|
||||
"vite-node",
|
||||
"why-is-node-running"
|
||||
],
|
||||
"optionalPeers": [
|
||||
"happy-dom"
|
||||
],
|
||||
"bin": true
|
||||
},
|
||||
"w3c-keyname@2.2.8": {
|
||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
|
||||
},
|
||||
"whatwg-mimetype@3.0.0": {
|
||||
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="
|
||||
},
|
||||
"why-is-node-running@2.3.0": {
|
||||
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
|
||||
"dependencies": [
|
||||
"siginfo",
|
||||
"stackback"
|
||||
],
|
||||
"bin": true
|
||||
},
|
||||
"yaml@2.9.0": {
|
||||
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
|
||||
"bin": true
|
||||
@@ -1037,7 +1406,7 @@
|
||||
"npm:decodal-codemirror@0.3.0",
|
||||
"npm:devalue@5.6.4",
|
||||
"npm:set-cookie-parser@2.7.2",
|
||||
"npm:shiki@3.13.0",
|
||||
"npm:shiki@4.4.2",
|
||||
"npm:svelte-check@4.3.4",
|
||||
"npm:svelte@5.45.6",
|
||||
"npm:typescript@5.9.3",
|
||||
@@ -1046,7 +1415,12 @@
|
||||
"packageJson": {
|
||||
"dependencies": [
|
||||
"npm:@fontsource/ibm-plex-mono@5.3.0",
|
||||
"npm:@humanspeak/svelte-markdown@1.9.1",
|
||||
"npm:@testing-library/svelte@5.2.8",
|
||||
"npm:gen-interface-jp@0.8.0",
|
||||
"npm:happy-dom@18.0.1",
|
||||
"npm:shiki@4.4.2",
|
||||
"npm:vitest@3.2.4",
|
||||
"npm:yaml@2.9.0"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,14 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fontsource/ibm-plex-mono": "5.3.0",
|
||||
"@humanspeak/svelte-markdown": "1.9.1",
|
||||
"gen-interface-jp": "0.8.0",
|
||||
"shiki": "4.4.2",
|
||||
"yaml": "2.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/svelte": "5.2.8",
|
||||
"happy-dom": "18.0.1",
|
||||
"vitest": "3.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
{:else if item.kind === 'user'}
|
||||
<div class="user-message">
|
||||
<span class="user-prompt" aria-hidden="true">></span>
|
||||
<div><RichMarkdown text={item.body || '—'} /></div>
|
||||
<div><RichMarkdown text={item.body || '—'} streamId={item.id} /></div>
|
||||
</div>
|
||||
{:else if item.kind === 'activity'}
|
||||
<p class="activity-summary">{item.body || '—'}</p>
|
||||
@@ -142,7 +142,7 @@
|
||||
{:else if item.kind === 'run_stats'}
|
||||
<p class="run-stats">{item.body}</p>
|
||||
{:else if shouldRenderMarkdown(item)}
|
||||
<RichMarkdown text={item.body || '—'} />
|
||||
<RichMarkdown text={item.body || '—'} streamId={item.id} />
|
||||
{:else}
|
||||
<p class="console-plain-text">{item.body || '—'}</p>
|
||||
{/if}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
let {
|
||||
href = "",
|
||||
title,
|
||||
children,
|
||||
}: {
|
||||
href?: string;
|
||||
title?: string;
|
||||
children?: Snippet;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<a {href} {title} target="_blank" rel="noreferrer">
|
||||
{@render children?.()}
|
||||
</a>
|
||||
@@ -0,0 +1,70 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { cleanup, render, waitFor } from "@testing-library/svelte";
|
||||
import { afterEach, expect, test } from "vitest";
|
||||
import RichMarkdown from "./RichMarkdown.svelte";
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
test("preserves safe links, blocks raw HTML, and renders Shiki code", async () => {
|
||||
const source = [
|
||||
"[unsafe](javascript:alert(1)) and [safe](https://example.com)",
|
||||
"",
|
||||
'<img src="x" onerror="alert(1)">',
|
||||
"",
|
||||
"```ts",
|
||||
"const answer: number = 42;",
|
||||
"```",
|
||||
].join("\n");
|
||||
const { container } = render(RichMarkdown, {
|
||||
text: source,
|
||||
streamId: "message-security",
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelectorAll("a")).toHaveLength(2);
|
||||
expect(container.querySelector("pre.shiki code span")).not.toBeNull();
|
||||
});
|
||||
|
||||
const [unsafe, safe] = container.querySelectorAll("a");
|
||||
expect(unsafe.getAttribute("href")).toBe("");
|
||||
expect(safe.getAttribute("href")).toBe("https://example.com");
|
||||
expect(safe.getAttribute("target")).toBe("_blank");
|
||||
expect(safe.getAttribute("rel")).toBe("noreferrer");
|
||||
expect(container.querySelector("img")).toBeNull();
|
||||
expect(container.querySelector("script")).toBeNull();
|
||||
});
|
||||
|
||||
test("keeps completed DOM nodes while a later markdown block grows", async () => {
|
||||
const initial = [
|
||||
"# Stable heading",
|
||||
"",
|
||||
"This paragraph is already complete.",
|
||||
"",
|
||||
"The final paragraph is stream",
|
||||
].join("\n");
|
||||
const { container, rerender } = render(RichMarkdown, {
|
||||
text: initial,
|
||||
streamId: "message-1",
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector("h1")?.textContent).toBe("Stable heading");
|
||||
expect(container.querySelectorAll("p")).toHaveLength(2);
|
||||
});
|
||||
const heading = container.querySelector("h1");
|
||||
const completedParagraph = container.querySelector("p");
|
||||
|
||||
await rerender({
|
||||
text: `${initial}ed incrementally.`,
|
||||
streamId: "message-1",
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(container.querySelectorAll("p")[1]?.textContent).toBe(
|
||||
"The final paragraph is streamed incrementally.",
|
||||
);
|
||||
});
|
||||
|
||||
expect(container.querySelector("h1")).toBe(heading);
|
||||
expect(container.querySelector("p")).toBe(completedParagraph);
|
||||
});
|
||||
@@ -1,41 +1,49 @@
|
||||
<script module lang="ts">
|
||||
import {
|
||||
createShikiHighlighter,
|
||||
setShikiHighlighter,
|
||||
} from "@humanspeak/svelte-markdown/extensions/shiki";
|
||||
import bash from "shiki/langs/bash.mjs";
|
||||
import javascript from "shiki/langs/javascript.mjs";
|
||||
import json from "shiki/langs/json.mjs";
|
||||
import python from "shiki/langs/python.mjs";
|
||||
import rust from "shiki/langs/rust.mjs";
|
||||
import typescript from "shiki/langs/typescript.mjs";
|
||||
import kanagawaWave from "shiki/themes/kanagawa-wave.mjs";
|
||||
|
||||
setShikiHighlighter(
|
||||
createShikiHighlighter({
|
||||
themes: [kanagawaWave],
|
||||
langs: [bash, javascript, json, python, rust, typescript],
|
||||
}),
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { markdownToHtml } from "$lib/workspace/console/markdown";
|
||||
import SvelteMarkdown, {
|
||||
buildUnsupportedHTML,
|
||||
type Renderers,
|
||||
} from "@humanspeak/svelte-markdown";
|
||||
import { ShikiCode } from "@humanspeak/svelte-markdown/extensions/shiki";
|
||||
import MarkdownLink from "$lib/workspace/console/MarkdownLink.svelte";
|
||||
|
||||
type Props = {
|
||||
text: string;
|
||||
streamId?: string | number;
|
||||
class?: string;
|
||||
};
|
||||
|
||||
let { text, class: className = "" }: Props = $props();
|
||||
let html = $state("");
|
||||
let rendering = $state(false);
|
||||
let { text, streamId = "static", class: className = "" }: Props = $props();
|
||||
|
||||
async function render(value: string): Promise<void> {
|
||||
const current = value;
|
||||
rendering = true;
|
||||
try {
|
||||
const next = await markdownToHtml(current);
|
||||
if (text === current) {
|
||||
html = next;
|
||||
}
|
||||
} finally {
|
||||
if (text === current) {
|
||||
rendering = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
void render(text);
|
||||
});
|
||||
const renderers = {
|
||||
code: ShikiCode,
|
||||
html: buildUnsupportedHTML(),
|
||||
link: MarkdownLink,
|
||||
} satisfies Partial<Renderers>;
|
||||
</script>
|
||||
|
||||
<div class={`rich-markdown ${className}`} class:is-rendering={rendering}>
|
||||
{#if html}
|
||||
{@html html}
|
||||
{:else}
|
||||
<p>{text}</p>
|
||||
{/if}
|
||||
<div class={`rich-markdown ${className}`}>
|
||||
<SvelteMarkdown source={text} {streamId} {renderers} streaming />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { markdownToHtml } from "./markdown.ts";
|
||||
|
||||
declare const Deno: {
|
||||
test(name: string, fn: () => void | Promise<void>): void;
|
||||
};
|
||||
|
||||
function assert(condition: unknown, message: string): asserts condition {
|
||||
if (!condition) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
Deno.test("markdownToHtml escapes raw html and renders basic markdown", async () => {
|
||||
const html = await markdownToHtml(
|
||||
"# Title\n\nhello **world** `<x>`\n\n<script>bad()</script>",
|
||||
);
|
||||
assert(html.includes("<h1>Title</h1>"), "heading should render");
|
||||
assert(html.includes("<strong>world</strong>"), "strong should render");
|
||||
assert(
|
||||
html.includes("<script>bad()</script>"),
|
||||
"raw html should be escaped",
|
||||
);
|
||||
assert(
|
||||
!html.includes("<script>bad()</script>"),
|
||||
"raw html must not pass through",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("markdownToHtml renders fenced code through shiki", async () => {
|
||||
const html = await markdownToHtml("```ts\nconst answer: number = 42;\n```");
|
||||
assert(
|
||||
html.includes("shiki"),
|
||||
"highlighted code should include shiki markup",
|
||||
);
|
||||
assert(html.includes("answer"), "code content should be present");
|
||||
});
|
||||
@@ -1,225 +0,0 @@
|
||||
import { codeToHtml } from "shiki";
|
||||
|
||||
const SHIKI_THEME = "kanagawa-wave";
|
||||
|
||||
export async function markdownToHtml(markdown: string): Promise<string> {
|
||||
if (!markdown.trim()) {
|
||||
return "";
|
||||
}
|
||||
const blocks = splitFencedCode(markdown);
|
||||
const html: string[] = [];
|
||||
let textBuffer: string[] = [];
|
||||
|
||||
async function flushText(): Promise<void> {
|
||||
if (textBuffer.length === 0) {
|
||||
return;
|
||||
}
|
||||
html.push(renderMarkdownText(textBuffer.join("\n")));
|
||||
textBuffer = [];
|
||||
}
|
||||
|
||||
for (const block of blocks) {
|
||||
if (block.kind === "text") {
|
||||
textBuffer.push(block.text);
|
||||
continue;
|
||||
}
|
||||
await flushText();
|
||||
html.push(await highlightCode(block.code, block.lang));
|
||||
}
|
||||
await flushText();
|
||||
return html.join("\n");
|
||||
}
|
||||
|
||||
type MarkdownBlock =
|
||||
| { kind: "text"; text: string }
|
||||
| { kind: "code"; lang: string; code: string };
|
||||
|
||||
function splitFencedCode(markdown: string): MarkdownBlock[] {
|
||||
const lines = markdown.split(/\r?\n/);
|
||||
const blocks: MarkdownBlock[] = [];
|
||||
let text: string[] = [];
|
||||
let code: string[] | null = null;
|
||||
let lang = "text";
|
||||
|
||||
for (const line of lines) {
|
||||
const fence = line.match(/^```\s*([^`]*)\s*$/);
|
||||
if (fence) {
|
||||
if (code) {
|
||||
blocks.push({ kind: "text", text: text.join("\n") });
|
||||
text = [];
|
||||
blocks.push({ kind: "code", lang, code: code.join("\n") });
|
||||
code = null;
|
||||
lang = "text";
|
||||
} else {
|
||||
if (text.length > 0) {
|
||||
blocks.push({ kind: "text", text: text.join("\n") });
|
||||
text = [];
|
||||
}
|
||||
lang = normalizeLanguage(fence[1]);
|
||||
code = [];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (code) {
|
||||
code.push(line);
|
||||
} else {
|
||||
text.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (code) {
|
||||
text.push("```" + (lang === "text" ? "" : lang));
|
||||
text.push(...code);
|
||||
}
|
||||
if (text.length > 0) {
|
||||
blocks.push({ kind: "text", text: text.join("\n") });
|
||||
}
|
||||
|
||||
return blocks.filter((block) =>
|
||||
block.kind === "code" || block.text.trim().length > 0
|
||||
);
|
||||
}
|
||||
|
||||
function renderMarkdownText(markdown: string): string {
|
||||
const lines = markdown.split(/\r?\n/);
|
||||
const html: string[] = [];
|
||||
let paragraph: string[] = [];
|
||||
let list: string[] = [];
|
||||
let blockquote: string[] = [];
|
||||
|
||||
function flushParagraph(): void {
|
||||
if (paragraph.length === 0) {
|
||||
return;
|
||||
}
|
||||
html.push(`<p>${paragraph.map(renderInline).join("<br>")}</p>`);
|
||||
paragraph = [];
|
||||
}
|
||||
|
||||
function flushList(): void {
|
||||
if (list.length === 0) {
|
||||
return;
|
||||
}
|
||||
html.push(
|
||||
`<ul>${
|
||||
list.map((item) => `<li>${renderInline(item)}</li>`).join("")
|
||||
}</ul>`,
|
||||
);
|
||||
list = [];
|
||||
}
|
||||
|
||||
function flushBlockquote(): void {
|
||||
if (blockquote.length === 0) {
|
||||
return;
|
||||
}
|
||||
html.push(
|
||||
`<blockquote>${blockquote.map(renderInline).join("<br>")}</blockquote>`,
|
||||
);
|
||||
blockquote = [];
|
||||
}
|
||||
|
||||
function flushAll(): void {
|
||||
flushParagraph();
|
||||
flushList();
|
||||
flushBlockquote();
|
||||
}
|
||||
|
||||
for (const rawLine of lines) {
|
||||
const line = rawLine.trimEnd();
|
||||
if (!line.trim()) {
|
||||
flushAll();
|
||||
continue;
|
||||
}
|
||||
|
||||
const heading = line.match(/^(#{1,4})\s+(.+)$/);
|
||||
if (heading) {
|
||||
flushAll();
|
||||
const level = heading[1].length;
|
||||
html.push(`<h${level}>${renderInline(heading[2])}</h${level}>`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const listItem = line.match(/^\s*[-*]\s+(.+)$/);
|
||||
if (listItem) {
|
||||
flushParagraph();
|
||||
flushBlockquote();
|
||||
list.push(listItem[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
const quote = line.match(/^>\s?(.*)$/);
|
||||
if (quote) {
|
||||
flushParagraph();
|
||||
flushList();
|
||||
blockquote.push(quote[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
flushList();
|
||||
flushBlockquote();
|
||||
paragraph.push(line);
|
||||
}
|
||||
flushAll();
|
||||
return html.join("\n");
|
||||
}
|
||||
|
||||
function renderInline(value: string): string {
|
||||
let escaped = escapeHtml(value);
|
||||
escaped = escaped.replace(/`([^`]+)`/g, "<code>$1</code>");
|
||||
escaped = escaped.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
|
||||
escaped = escaped.replace(/\b(https?:\/\/[^\s<]+[^\s<.,;:)])/g, (url) => {
|
||||
const safe = escapeAttribute(url);
|
||||
return `<a href="${safe}" rel="noreferrer" target="_blank">${url}</a>`;
|
||||
});
|
||||
return escaped;
|
||||
}
|
||||
|
||||
async function highlightCode(code: string, lang: string): Promise<string> {
|
||||
try {
|
||||
return await codeToHtml(code, {
|
||||
lang: lang || "text",
|
||||
theme: SHIKI_THEME,
|
||||
});
|
||||
} catch {
|
||||
return `<pre class="shiki fallback"><code>${escapeHtml(code)}</code></pre>`;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeLanguage(value: string | undefined): string {
|
||||
const raw = value?.trim().split(/\s+/, 1)[0] ?? "";
|
||||
if (!raw) {
|
||||
return "text";
|
||||
}
|
||||
switch (raw) {
|
||||
case "sh":
|
||||
case "shell":
|
||||
case "zsh":
|
||||
return "bash";
|
||||
case "ts":
|
||||
return "typescript";
|
||||
case "js":
|
||||
return "javascript";
|
||||
default:
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(value: string): string {
|
||||
return value.replace(/[&<>"]/g, (char) => {
|
||||
switch (char) {
|
||||
case "&":
|
||||
return "&";
|
||||
case "<":
|
||||
return "<";
|
||||
case ">":
|
||||
return ">";
|
||||
case '"':
|
||||
return """;
|
||||
default:
|
||||
return char;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function escapeAttribute(value: string): string {
|
||||
return escapeHtml(value).replace(/'/g, "'");
|
||||
}
|
||||
@@ -446,7 +446,9 @@ Deno.test("Worker Console renders markdown only for message rows", async () => {
|
||||
consoleLine.includes("font-size: 12px;") &&
|
||||
consoleLine.includes("line-height: 1.1;") &&
|
||||
consoleLine.includes("{:else if shouldRenderMarkdown(item)}") &&
|
||||
consoleLine.includes("<RichMarkdown text={item.body || '—'} />") &&
|
||||
consoleLine.includes(
|
||||
"<RichMarkdown text={item.body || '—'} streamId={item.id} />",
|
||||
) &&
|
||||
!consoleLine.includes("{@html"),
|
||||
"Console should keep markdown rendering to message bodies, safely project Bash ANSI, and render other tool text literally",
|
||||
);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { svelteTesting } from "@testing-library/svelte/vite";
|
||||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import { defineConfig } from "vite";
|
||||
import { CODEMIRROR_VITE_DEDUPE } from "./src/lib/workspace/config-source/vite-dedupe";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
plugins: [sveltekit(), svelteTesting()],
|
||||
|
||||
resolve: {
|
||||
dedupe: CODEMIRROR_VITE_DEDUPE,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { defineConfig, mergeConfig } from "vitest/config";
|
||||
import viteConfig from "./vite.config.ts";
|
||||
|
||||
export default mergeConfig(
|
||||
viteConfig,
|
||||
defineConfig({
|
||||
test: {
|
||||
include: ["src/**/*.browser.spec.ts"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
Reference in New Issue
Block a user