diff --git a/index.html b/index.html new file mode 100644 index 0000000..54fd919 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + new-markdown + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f2f010a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6977 @@ +{ + "name": "new-markdown", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "new-markdown", + "version": "0.1.0", + "dependencies": { + "@codemirror/lang-markdown": "6.5.2", + "@codemirror/language-data": "6.5.2", + "@codemirror/theme-one-dark": "6.1.3", + "@milkdown/kit": "7.23.0", + "@milkdown/plugin-math": "7.5.9", + "@tauri-apps/api": "^2.12.4", + "@tauri-apps/plugin-dialog": "^2.2.0", + "codemirror": "6.0.2", + "katex": "0.16.11", + "mermaid": "12.3.0", + "react": "18.3.1", + "react-dom": "18.3.1" + }, + "devDependencies": { + "@tauri-apps/cli": "^2.2.0", + "@types/react": "18.3.11", + "@types/react-dom": "18.3.1", + "@vitejs/plugin-react": "4.3.3", + "jsdom": "25.0.1", + "typescript": "5.6.3", + "vite": "5.4.11", + "vitest": "2.1.5" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-2.1.0.tgz", + "integrity": "sha512-sdg9NxU3zR4Mnawfbc/x6GB5Wf17WYud5qOuEuxXjaKpYpMkISSJEjItGebXJ2bQ4DIcly4NYH23mtkGJjvKUw==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.8.0", + "tinyexec": "^1.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/install-pkg/node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.13", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.13.tgz", + "integrity": "sha512-j1nvOQCZYSgp7HLmisnCXFTpVvFODiijQ9QHkORfGKWH6YDtskTEeCJS7eV545GZ9UBzrq0e2xsOd5QQ5PjIqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.13", + "@babel/helper-compilation-targets": "^7.29.13", + "@babel/helper-module-transforms": "^7.29.13", + "@babel/helpers": "^7.29.13", + "@babel/parser": "^7.29.13", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.13", + "@babel/types": "^7.29.11", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.14.tgz", + "integrity": "sha512-qSY56jgW5JnSXzuekLVil6zaOQxOCtOHidr65KkaMBw772IuAY28Qx4ZykAcDn8+FRF15qk80XzKwgSc/RYW6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.14", + "@babel/types": "^7.29.14", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.13", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.13.tgz", + "integrity": "sha512-8WxJ4/Vmes3ghacj8VOJy3NW8eyHiFY/4thU/LSBuBE470+igjR/j1ZTNn8fV5VdNrLx6iXUwig526UdOvfP0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.14", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.14.tgz", + "integrity": "sha512-2XDvQVd9JESaOgGc4jT2/jquTAO7ppA5noTZQqH+MmZ89yjCzScLwtCPbWtkPZylL+TLWR49IwWmk+QkRR4GsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.14" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.14", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.14.tgz", + "integrity": "sha512-CXvKMFvM80ihI7Vox9jb+kQjnyjESQNPM+vB7U0Zz6TWuZA+Z/FL0QPMH300h33qJtIx+REeBhXqWOPW48TcAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.14", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.14.tgz", + "integrity": "sha512-6E3Mi1r0B0umq6vmZa4/78q+64fqO2YY0THUdjDPKUCKhNb0yQy5NQIaPHCSD3ryTgiTss//P4JsWS80AsZ6LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.14" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.14", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.14.tgz", + "integrity": "sha512-VL220vXuyO2z3rNIQwY7ftj9UwpqOt+33sH+sBWkOekbsSR2g7EEMnOx24ZlCH0xOA3DM/33SifVFGbnJD8r/w==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.14" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.14", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.14.tgz", + "integrity": "sha512-RAdQJrBgmIH1FWvN0X+1hoDxzMzlP4cv/1Zi4dn4tG1H0cTb+rw7CzUxQJhp1f4ANd8j5vH3fy8BAWFGkBDEsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.14", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.14", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.14", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.14", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.14.tgz", + "integrity": "sha512-UjI/dKmwJwT9pOszJitq2G6EObZPnsZUfdCr92z2TlF3EZK9J3EdfOKUrCzHl6wFthbzwhzl1Soc/UIwxRiq6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.14", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT" + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-13.2.0.tgz", + "integrity": "sha512-bA9dvWlhAUcHkNwU+8w9yiUxJPlj/Lm3VqS7MD+NbIR/7LmpNLuK/AWNFdCo/T3SK5ND0/UHf3IJvl/Jn/i6yg==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "13.2.0", + "@chevrotain/types": "13.2.0" + } + }, + "node_modules/@chevrotain/gast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-13.2.0.tgz", + "integrity": "sha512-bCARdAsG+eEbOveSXcOAC7pVxA04I1ionzeMOwIYf5NX7SaS7zgn4Dgug2BSqoL+iyKeMNSorQjsFSHJHsCNwg==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "13.2.0" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-13.2.0.tgz", + "integrity": "sha512-kxpUkLtiaK09ph+dib+Yvm+3sWSnuwlo25gqfKRgTPNmF6H7uW4gVkMjaRdtnN783S9sM6vUNWh9CsxYX4QwKw==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-13.2.0.tgz", + "integrity": "sha512-7qrYHRlKfWf2AvBfJi5eVOrKAkbxvMFsy/iIHTGIiApNcEecCaVIdR+mIQhyCBsTDJxBz4JWXHMo6krbhR9hVg==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-13.2.0.tgz", + "integrity": "sha512-SzKYY68rseOrb9KILVzPsl6SjkQtdWw01SRGB5aCVI5kFcHltQsOYV3JB0Ffst72DgkvHCyDQ0NLwxtmCCf97Q==", + "license": "Apache-2.0" + }, + "node_modules/@codemirror/autocomplete": { + "version": "6.20.4", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.4.tgz", + "integrity": "sha512-yF8RhOf2SXlg00+qtupzLhrglcas61boqaONiNcbPIebHCpJocpqTBA6dyrtUrQO47hqyTdeob/3XnYilT7TaQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.11.1.tgz", + "integrity": "sha512-O/4hG3SC1YwcmQ0d2UVNDs+AsaNWd1iHVxbTeEBuqH+6bExAiPK3iS/BvpY6rZGURALv4ZD3sIgcCmRvw3ehBg==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.7.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-angular": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@codemirror/lang-angular/-/lang-angular-0.1.4.tgz", + "integrity": "sha512-oap+gsltb/fzdlTQWD6BFF4bSLKcDnlxDsLdePiJpCVNKWXSTAbiiQeYI3UmES+BLAdkmIC1WjyztC1pi/bX4g==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.3" + } + }, + "node_modules/@codemirror/lang-cpp": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.3.tgz", + "integrity": "sha512-URM26M3vunFFn9/sm6rzqrBzDgfWuDixp85uTY49wKudToc2jTHUrKIGGKs+QWND+YLofNNZpxcNGRynFJfvgA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/cpp": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", + "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } + }, + "node_modules/@codemirror/lang-go": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-go/-/lang-go-6.0.1.tgz", + "integrity": "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/go": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.12.tgz", + "integrity": "sha512-pw2ReWKUqSkbvh76RAT4NYxiogRu+PWkR2ukAwO9uOgrm8uipkzjtKKtNpyeAQwHOqxEeSvAXZ6vr3AfyB9y/w==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.12" + } + }, + "node_modules/@codemirror/lang-java": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.2.tgz", + "integrity": "sha512-m5Nt1mQ/cznJY7tMfQTJchmrjdjQ71IDs+55d1GAa8DGaB8JXWsVCkVT284C3RTASaY43YknrK2X3hPO/J3MOQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/java": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.5.tgz", + "integrity": "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-jinja": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-jinja/-/lang-jinja-6.0.1.tgz", + "integrity": "sha512-P5kyHLObzjtbGj16h+hyvZTxJhSjBEeSx4wMjbnAf3b0uwTy2+F0zGjMZL4PQOm/mh2eGZ5xUDVZXgwP783Nsw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.2.0", + "@lezer/lr": "^1.4.0" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz", + "integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-less": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-less/-/lang-less-6.0.2.tgz", + "integrity": "sha512-EYdQTG22V+KUUk8Qq582g7FMnCZeEHsyuOJisHRft/mQ+ZSZ2w51NupvDUHiqtsOy7It5cHLPGfHQLpMh9bqpQ==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-liquid": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.3.3.tgz", + "integrity": "sha512-U9EnyzWuAx1TX3MZSKDXydKH734n1Aogk/ijKdW+jdIwmbf9zSPQYOIKggC/b2PTRjQb7ddvMktmxnfTLuv/SQ==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.1" + } + }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.5.2.tgz", + "integrity": "sha512-AwBOdkWYuA//WcM0xO5PfHPUcmz/O2i5o0Nsg1U69SII/loCJlFI1Romd9xp2HYb1kYJRGZotyqRghuHH5n8Kw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.7.1", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.3.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/markdown": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-php": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.2.tgz", + "integrity": "sha512-ZKy2v1n8Fc8oEXj0Th0PUMXzQJ0AIR6TaZU+PbDHExFwdu+guzOA4jmCHS1Nz4vbFezwD7LyBdDnddSJeScMCA==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/php": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-python": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.2.1.tgz", + "integrity": "sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.3.2", + "@codemirror/language": "^6.8.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/python": "^1.1.4" + } + }, + "node_modules/@codemirror/lang-rust": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.2.tgz", + "integrity": "sha512-EZaGjCUegtiU7kSMvOfEZpaCReowEf3yNidYu7+vfuGTm9ow4mthAparY5hisJqOHmJowVH3Upu+eJlUji6qqA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/rust": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sass": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sass/-/lang-sass-6.0.2.tgz", + "integrity": "sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/sass": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sql": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.10.0.tgz", + "integrity": "sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-vue": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-vue/-/lang-vue-0.1.3.tgz", + "integrity": "sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.1" + } + }, + "node_modules/@codemirror/lang-wast": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-wast/-/lang-wast-6.0.2.tgz", + "integrity": "sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-xml": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz", + "integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/xml": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-yaml": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.3.tgz", + "integrity": "sha512-AZ8DJBuXGVHybpBQhmZtgew5//4hv3tdkXnr3vDmOUMJRuB6vn/uuwtmTOTlqEaQFg3hQSVeA90NmvIQyUV6FQ==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.2.0", + "@lezer/lr": "^1.0.0", + "@lezer/yaml": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.13.1.tgz", + "integrity": "sha512-zfvU2r3TyylQLMj/te+5CnQ0rSqZi8B1oTCBbQkagcLW4Xc6imab6qN+pEJhsuNOLaJqiRyBXp9UhWA1DhVvDw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/streamparser": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/language-data": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/language-data/-/language-data-6.5.2.tgz", + "integrity": "sha512-CPkWBKrNS8stYbEU5kwBwTf3JB1kghlbh4FSAwzGW2TEscdeHHH4FGysREW86Mqnj3Qn09s0/6Ea/TutmoTobg==", + "license": "MIT", + "dependencies": { + "@codemirror/lang-angular": "^0.1.0", + "@codemirror/lang-cpp": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-go": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-java": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/lang-jinja": "^6.0.0", + "@codemirror/lang-json": "^6.0.0", + "@codemirror/lang-less": "^6.0.0", + "@codemirror/lang-liquid": "^6.0.0", + "@codemirror/lang-markdown": "^6.0.0", + "@codemirror/lang-php": "^6.0.0", + "@codemirror/lang-python": "^6.0.0", + "@codemirror/lang-rust": "^6.0.0", + "@codemirror/lang-sass": "^6.0.0", + "@codemirror/lang-sql": "^6.0.0", + "@codemirror/lang-vue": "^0.1.1", + "@codemirror/lang-wast": "^6.0.0", + "@codemirror/lang-xml": "^6.0.0", + "@codemirror/lang-yaml": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/legacy-modes": "^6.4.0" + } + }, + "node_modules/@codemirror/legacy-modes": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.5.5.tgz", + "integrity": "sha512-9ltT214oMb3Y1w5eAZMSigzrjzZnMI2Wa3Feq73rU/i4C56MkwrpfswfQYOr28C5pXr6dWwspNTMyeHXlzWMxg==", + "license": "MIT", + "dependencies": { + "@codemirror/streamparser": "^6.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.9.8", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.8.tgz", + "integrity": "sha512-qNvtcE73xUto/D1RvtgSRI4A1Hg8ekxlvtZpjHpdpisLBnhyu82EUEJMEgaxkjuQCA8vqnrylENWKOsEDCOHcw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.42.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.2.tgz", + "integrity": "sha512-gUYkYhT2+n/+VGZ+8EzE5WFkYZUZYm1VOKDudIsNqh42uRVQJ0a6Yss9sdKT3MeOYfuL1N6AZA57oza0Oyr0LA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.37.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.7.6", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.6.tgz", + "integrity": "sha512-kAz+AncRtKuIknedxT1bq4XwXv4UowhbkHU1myPrtVb/jZtImWuV5BXzv5vK6i3kYACsdiZiQKFQQ5Mq7elW8w==", + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/streamparser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/streamparser/-/streamparser-6.0.0.tgz", + "integrity": "sha512-JTFPF6xrfjt0mnfGPgzcLiMwYmvIyNaoizp8BYzv8FE8KrT6GBGDZ190rtt+O7Wke3gG/MFHyiY9YGNeimof4w==", + "license": "MIT" + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz", + "integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.43.15", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.15.tgz", + "integrity": "sha512-HHsfpqFeHyXLs983pSRe38Xajs0vFWZQ2BuX0m7Ki8w3jZ5iD8cuR3lBz2/5/X53Dhf32SBHKh6rtSTB6tKeGw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.7.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.7.tgz", + "integrity": "sha512-JZHlwdID+dy+lTgbYC8NEC4zeugqeYsc6jewvzb4c58kHauJn+X7rNwQjxz5p2qSjqaEeQoLkCIQ9v/H4PK0/w==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^2.0.1", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.3.tgz", + "integrity": "sha512-lhTtjtoEArWBjismtfS761S9Hlyn+nIZqOZVYoZ1Xn82PMNMVnk+jj/NhC4fAXGTs7ydONcJiR5vyQBTMDu27g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lezer/common": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.5.tgz", + "integrity": "sha512-Pw7PVCndruF1pb3ebCxpSVpkMHSDjwRCLcTRw+RizUKco5QbWylwq2g4lnG/RYN7yTTQDXE9F77MwtkAyphrjg==", + "license": "MIT" + }, + "node_modules/@lezer/cpp": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.6.tgz", + "integrity": "sha512-vh9gWWJOXFVY8HBHK3Twzq8MgwG2iN4GSyzBP9sCGTe37P15x2R14VaBQk0VA0ezTRN1KHYBBsHhvpGZ2Xy/pA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/css": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.9.tgz", + "integrity": "sha512-ZmzgvTOBdJWGIsY/ItAfN7UW8DV802oZG+jeG6E508SwEzz5YhuAajptpWPICvIyqYAD2+VjMdOS40GgGkyEOQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/go": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.1.tgz", + "integrity": "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.5.tgz", + "integrity": "sha512-O1GMVKgtf5YspFaRzpmqkVgMtIk2HG9uMAbH6wdAIdNh3TVzCsch/+cRi+6l2//UGDKe6NB9BW3cvuR5ezMQ0w==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz", + "integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/java": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.5.tgz", + "integrity": "sha512-JppTd1iKHpeNlLYw/Zl8JX7zSY5HqAzK4zZ05lpn8l8Sk7Fo5KAKiDiMiezKoT5lfeC2xZf8HeKp1tSctj4G6Q==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.6.tgz", + "integrity": "sha512-sEvOqpl4vJQca0NugSQK02vQPbc5KrvoojnYGoqqFgFO0MtcYhwGiHKVEB+LuXYJnfyXo4QPA8ztbrEa4Fw5NA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", + "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.12", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.12.tgz", + "integrity": "sha512-On9HU4oMMiHPMkQDgoTnGahjgG5n/MkN38CgG77sMraKLL+3JBbeQNi1FcCXV9QRqwF9/BUXP3caHyJC1fBOTQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/markdown": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.8.1.tgz", + "integrity": "sha512-M5YmEcKWO4mJ45Y1hECwqyu8cLv25EiXOK554PVOvDOWOP0olwelHHQUWr9sjF+d1bENVhy0nfJ8E57XZUTiXg==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@lezer/php": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.6.tgz", + "integrity": "sha512-QJ2xNXPmsm/Z3IpThq8fnJrEIVpxhsIoj6GZBW0JYEd/l9zxpJZW216X4fzqQY4vgpdGIumypvI4uQjd4tnYtw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.1.0" + } + }, + "node_modules/@lezer/python": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.19.tgz", + "integrity": "sha512-MhQIURHRytsNzP/YXnqpYKW6la6voAH3kyplTOOiCdjyFY6cWWGFVmYVdHIPrElqSDf4iCDktQCockB9FxuhzQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/rust": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.3.tgz", + "integrity": "sha512-XxErOjZzQ7yJt1agUT4fu9qQvESZ3acgoxpPaPTPOiUx+duCjaVAtZGFIgphkHxlN05djdVAIOy/wItShMEjqQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/sass": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/sass/-/sass-1.1.0.tgz", + "integrity": "sha512-3mMGdCTUZ/84ArHOuXWQr37pnf7f+Nw9ycPUeKX+wu19b7pSMcZGLbaXwvD2APMBDOGxPmpK/O6S1v1EvLoqgQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/xml": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz", + "integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/yaml": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.4.tgz", + "integrity": "sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.4.0" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.4.tgz", + "integrity": "sha512-Wy0V7+SGUjnF9/TkiM1hKVDPj7jKXduPNboMVtHTA8dySMURWqfg/JZ9E2Sq8JgSJmkl7k7Qe9FLeMSrSraWmQ==", + "license": "MIT" + }, + "node_modules/@mermaid-js/parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-2.0.1.tgz", + "integrity": "sha512-j37dj/h6p6pots1L7pLPPNuABEEu9WP4OYg9pW1g+nYG331j0+3canE9OagtYdytYvdSAMG+2fKU5cxep6LgjA==", + "license": "MIT", + "dependencies": { + "@chevrotain/types": "~13.2.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@milkdown/components": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/components/-/components-7.23.0.tgz", + "integrity": "sha512-KoGEk2MCrusUeVOQ5ag7O64GmT8aidvskKAkKT2szQA0VtxIgTJ60ughcuAkHibv9yd1FCiba1QBkck0rrlo4Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.5.1", + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/exception": "7.23.0", + "@milkdown/plugin-diff": "7.23.0", + "@milkdown/plugin-tooltip": "7.23.0", + "@milkdown/preset-commonmark": "7.23.0", + "@milkdown/preset-gfm": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/transformer": "7.23.0", + "@milkdown/utils": "7.23.0", + "@types/lodash-es": "^4.17.12", + "clsx": "^2.0.0", + "dompurify": "^3.2.5", + "lodash-es": "^4.17.21", + "nanoid": "^6.0.0", + "unist-util-visit": "^5.0.0", + "vue": "^3.5.20" + }, + "peerDependencies": { + "@codemirror/language": "^6", + "@codemirror/state": "^6", + "@codemirror/view": "^6" + } + }, + "node_modules/@milkdown/core": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/core/-/core-7.23.0.tgz", + "integrity": "sha512-4BpCjPYMg0KvuflgpRgqX2Cfz3HLmG+xPCJIvl2J2qlrzSE0h6f+eIqKAsUuf6u8nkh+HHFOhjBFiuT6SDBotQ==", + "license": "MIT", + "dependencies": { + "@milkdown/ctx": "7.23.0", + "@milkdown/exception": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/transformer": "7.23.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.3" + } + }, + "node_modules/@milkdown/ctx": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/ctx/-/ctx-7.23.0.tgz", + "integrity": "sha512-iyn9G4kHacCn/yRXvggUWqiXou5Aok7zBJaJ7BKKdAMjK9IQDZlsDKr+7Rh+aK1NrIfqHcVD+rg/Y0Qh/sCO1A==", + "license": "MIT", + "dependencies": { + "@milkdown/exception": "7.23.0" + } + }, + "node_modules/@milkdown/exception": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/exception/-/exception-7.23.0.tgz", + "integrity": "sha512-g+7qgfmD6UK8O2GGYsr8RIZDkF/7VR8rrSnDpMkanKxT9PIBizuc5Je0c+mhqZKvjsikxm+7kcqQStV+MpRpSw==", + "license": "MIT" + }, + "node_modules/@milkdown/kit": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/kit/-/kit-7.23.0.tgz", + "integrity": "sha512-WNu4cZXY33l224gLuyRWaQdPDotsPJ3yBn0+FGobaqH6aEt8G/QxIC1MIUV8Uxj07lMP6aIfaW4ilNLTjAMCmw==", + "license": "MIT", + "dependencies": { + "@milkdown/components": "7.23.0", + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/exception": "7.23.0", + "@milkdown/plugin-block": "7.23.0", + "@milkdown/plugin-clipboard": "7.23.0", + "@milkdown/plugin-cursor": "7.23.0", + "@milkdown/plugin-diff": "7.23.0", + "@milkdown/plugin-history": "7.23.0", + "@milkdown/plugin-indent": "7.23.0", + "@milkdown/plugin-listener": "7.23.0", + "@milkdown/plugin-slash": "7.23.0", + "@milkdown/plugin-streaming": "7.23.0", + "@milkdown/plugin-tooltip": "7.23.0", + "@milkdown/plugin-trailing": "7.23.0", + "@milkdown/plugin-upload": "7.23.0", + "@milkdown/preset-commonmark": "7.23.0", + "@milkdown/preset-gfm": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/transformer": "7.23.0", + "@milkdown/utils": "7.23.0" + } + }, + "node_modules/@milkdown/plugin-block": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-block/-/plugin-block-7.23.0.tgz", + "integrity": "sha512-JF9dEjucXXbFwJn9+KNrcjx+pHxXHjbkhUGm8/UkJD2wUakX4ee20wGelTIe5SrMgJWpeVn4+z+v+j+Aa6mzww==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.5.1", + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0", + "@types/lodash-es": "^4.17.12", + "lodash-es": "^4.17.21" + } + }, + "node_modules/@milkdown/plugin-clipboard": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-clipboard/-/plugin-clipboard-7.23.0.tgz", + "integrity": "sha512-9fse4q+Xsw+ME9aT9g9+TI1TZwp22t5OGI2WIAxDI7WxmtnJwzyMEim38429xrwg4zLwPKDpP/aecooA8oO/9g==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0" + } + }, + "node_modules/@milkdown/plugin-cursor": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-cursor/-/plugin-cursor-7.23.0.tgz", + "integrity": "sha512-t+olMXLiRbS2PZmh01H8ayXIP/eP8I9sqasPexqh4F3woKInbZ/FF0mKVsTF3ZNb1GMi6b4LzuahzMXrH7GbLw==", + "license": "MIT", + "dependencies": { + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0", + "prosemirror-drop-indicator": "^0.1.0" + } + }, + "node_modules/@milkdown/plugin-diff": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-diff/-/plugin-diff-7.23.0.tgz", + "integrity": "sha512-VHipPckWvmjXB+KK6clrQJTDWUFNVvPRgsAtz57hwCqjxgqJlZj6qR4DmdxOOB1pIOzFL8+wDqIwKwut61K7+w==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/transformer": "7.23.0", + "@milkdown/utils": "7.23.0" + } + }, + "node_modules/@milkdown/plugin-history": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-history/-/plugin-history-7.23.0.tgz", + "integrity": "sha512-Ii+5XmQRsquT5UllZW/GknsI/t7QgVk/3gHGnmZGogNO95i7e/qW03ubUz2b3RzJ6WuPNv+spRwuaK7LblcvwA==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0" + } + }, + "node_modules/@milkdown/plugin-indent": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-indent/-/plugin-indent-7.23.0.tgz", + "integrity": "sha512-FYoHv7N2iKLwEIwpOL7nXEw2ZfL/1iqpKKH88jcy0X+4x4P4SIsYgmoWBh3Hx+OOTb4oUqI8k+y4Fed+LwTBUQ==", + "license": "MIT", + "dependencies": { + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0" + } + }, + "node_modules/@milkdown/plugin-listener": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-listener/-/plugin-listener-7.23.0.tgz", + "integrity": "sha512-KmY1RmtRkou8nhxN0JeWXrKLXfdn9WDlLDhN+uJ2SLr36rECh+gUZ6s3AUMYP6X7fig8jlDS4h498hEH0wQn9A==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@types/lodash-es": "^4.17.12", + "lodash-es": "^4.17.21" + } + }, + "node_modules/@milkdown/plugin-math": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-math/-/plugin-math-7.5.9.tgz", + "integrity": "sha512-LzFZKNc7zm3uOTs9mEN/12/X+UdGoyQRp5Gt9GE7lPJ96jOZaGJD0vMtX0mTauTOmUxDQoQS0I7NW1g9UhC6qQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "dependencies": { + "@milkdown/exception": "7.5.9", + "@milkdown/utils": "7.5.9", + "@types/katex": "^0.16.0", + "katex": "^0.16.0", + "remark-math": "^6.0.0", + "tslib": "^2.5.0" + }, + "peerDependencies": { + "@milkdown/core": "^7.2.0", + "@milkdown/ctx": "^7.2.0", + "@milkdown/prose": "^7.2.0" + } + }, + "node_modules/@milkdown/plugin-math/node_modules/@milkdown/exception": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/@milkdown/exception/-/exception-7.5.9.tgz", + "integrity": "sha512-9g+WpiRjgLsVlHt7DotlUmKK9oT6Lsr5TgxE0NdDvtr81CC43mgNtoekI6rg/PatEBBXifDK1GJJ4LKnRSseVQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@milkdown/plugin-math/node_modules/@milkdown/utils": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/@milkdown/utils/-/utils-7.5.9.tgz", + "integrity": "sha512-udxaIdKm6pOiNACIKR7+NQ7Vj+QivhA5jcRqksEuQOfDFQBFcGaAhGEEiU1cKwE7fmP2ayigfD0IZ01rjLS2fA==", + "license": "MIT", + "dependencies": { + "@milkdown/exception": "7.5.9", + "nanoid": "^5.0.0", + "tslib": "^2.5.0" + }, + "peerDependencies": { + "@milkdown/core": "^7.2.0", + "@milkdown/ctx": "^7.2.0", + "@milkdown/prose": "^7.2.0", + "@milkdown/transformer": "^7.2.0" + } + }, + "node_modules/@milkdown/plugin-math/node_modules/nanoid": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.16.tgz", + "integrity": "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/@milkdown/plugin-slash": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-slash/-/plugin-slash-7.23.0.tgz", + "integrity": "sha512-oN0lAOcsjpA6OzjcPnikmMF/AxBabkyvye6D4uLrwvo96VwBR/BQRT5pvcMxxpY+SLcMpiCrSLnB9fT4XR36Sw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.5.1", + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0", + "@types/lodash-es": "^4.17.12", + "lodash-es": "^4.17.21" + } + }, + "node_modules/@milkdown/plugin-streaming": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-streaming/-/plugin-streaming-7.23.0.tgz", + "integrity": "sha512-rcWDkuysZSugw7xxAE3OB/CcaJiHNdohwmthmyTH8y5BYrGob+8R3wGQw9sYVIItvooEmSRbwisxkrhHWwgilg==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/plugin-diff": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0" + } + }, + "node_modules/@milkdown/plugin-tooltip": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-tooltip/-/plugin-tooltip-7.23.0.tgz", + "integrity": "sha512-254v/+RowQ8QfUm3QHIBRqf1glUwT6pmaZe+LM30Zys2lce6oXVhQxOC1atR3lKIwJg51VP5WLQJjooUgpXSTg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.5.1", + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0", + "@types/lodash-es": "^4.17.12", + "lodash-es": "^4.17.21" + } + }, + "node_modules/@milkdown/plugin-trailing": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-trailing/-/plugin-trailing-7.23.0.tgz", + "integrity": "sha512-jCx5tZflZTUyVj4A7osDdhf88Np0Q9gkgqVw9hq4VBuWrEeHRKR4rkYApHZnq3jX9cHVtlnXEIPc0gOh5N9+bA==", + "license": "MIT", + "dependencies": { + "@milkdown/ctx": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0" + } + }, + "node_modules/@milkdown/plugin-upload": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/plugin-upload/-/plugin-upload-7.23.0.tgz", + "integrity": "sha512-KHbE+bRQ/1ubWrye3F2e/N22VocpycdR8Vq287w12pkzjBjRBETtzg2HhIDtqSTAmDn1sxhJ00sJ+CiG00Gfdg==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/exception": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/utils": "7.23.0" + } + }, + "node_modules/@milkdown/preset-commonmark": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/preset-commonmark/-/preset-commonmark-7.23.0.tgz", + "integrity": "sha512-UQyt07Sja0oa4V6l6z+czAuQwce72lmcpNkBby6550s8g0TrXNrRAsTDr6jGRgC28fnj8rR5ID1hmmX9RDLhHg==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/exception": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/transformer": "7.23.0", + "@milkdown/utils": "7.23.0", + "remark-inline-links": "^7.0.0", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.1" + } + }, + "node_modules/@milkdown/preset-gfm": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/preset-gfm/-/preset-gfm-7.23.0.tgz", + "integrity": "sha512-lN8ZQH0QqME86ZlBkDOTn+f6IdMDWd9+17kHpeYxqWUfB+nAE7PH2O+3xE/uT/8f9CleK95AN3rFrSVwchd0Hg==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/exception": "7.23.0", + "@milkdown/preset-commonmark": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/transformer": "7.23.0", + "@milkdown/utils": "7.23.0", + "prosemirror-safari-ime-span": "^1.0.1", + "remark-gfm": "^4.0.1" + } + }, + "node_modules/@milkdown/prose": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/prose/-/prose-7.23.0.tgz", + "integrity": "sha512-HHju8O/T+U2Sy5AMHM78PLd2KTha+UYrZjesZjVF9+o5T559+wQFHKq5X/Ytk2XAeuen3uLQ07avfw4FbZ6HRg==", + "license": "MIT", + "dependencies": { + "@milkdown/exception": "7.23.0", + "prosemirror-changeset": "^2.3.1", + "prosemirror-commands": "^1.7.1", + "prosemirror-dropcursor": "^1.8.2", + "prosemirror-gapcursor": "^1.4.0", + "prosemirror-history": "^1.5.0", + "prosemirror-inputrules": "^1.5.1", + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-schema-list": "^1.5.1", + "prosemirror-state": "^1.4.4", + "prosemirror-tables": "^1.8.1", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.3" + } + }, + "node_modules/@milkdown/transformer": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/transformer/-/transformer-7.23.0.tgz", + "integrity": "sha512-vPljNdPrvjtnpd/CtIUwB36zgQF/oOgVdceWB3RL760mtrfQS0+IhmkcAPrz+w11ug8KIPJ/pJLxxJfD2Y4iqg==", + "license": "MIT", + "dependencies": { + "@milkdown/exception": "7.23.0", + "@milkdown/prose": "7.23.0", + "remark": "^15.0.1", + "unified": "^11.0.3" + } + }, + "node_modules/@milkdown/utils": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@milkdown/utils/-/utils-7.23.0.tgz", + "integrity": "sha512-4zPs0jo8vZajynmiFPTU3Er6tAOJru7GV6stCVxgGm7P2EFRyUpA4378JtrEyNhfwftMSNu4DGYI4ihCGejohg==", + "license": "MIT", + "dependencies": { + "@milkdown/core": "7.23.0", + "@milkdown/ctx": "7.23.0", + "@milkdown/exception": "7.23.0", + "@milkdown/prose": "7.23.0", + "@milkdown/transformer": "7.23.0", + "nanoid": "^6.0.0" + } + }, + "node_modules/@ocavue/utils": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@ocavue/utils/-/utils-1.12.0.tgz", + "integrity": "sha512-PzQ6biw5KN0AKQd0TzngftFTzs3Jy22/NrYXHBKd1C60tew2Z8X5RNCr6x5ajQOQKILW+AGHbItXeDyy50Fj9Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ocavue" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.68.3.tgz", + "integrity": "sha512-mqfypgH/liYjaSCoPI4erckUcROgZtmFUUmyOJ05oyayi/tVqOEYAzWP7ufqCoCT3xB31Fw4XIVO/jX42hYvKA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.68.3.tgz", + "integrity": "sha512-5tY+GC/1gpt79cKS2DQzu6iD824j6BmI4q5Zb6qftZ4kWqIQmvR3DD4eJ2Gclu6/nVMYDk2IVpqxypWOiAuWJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-x64": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-x64/-/rollup-android-x64-4.68.3.tgz", + "integrity": "sha512-nDBcQ/o3PMmGxmAzGBJFn+n1rb83Va9WSdFIq1AHmlEF3tuibVsyJ3kG5x13r7VIy6WI8SvzCdHVNSlSDIdj8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.68.3.tgz", + "integrity": "sha512-dra5zl0QWKkIkaMgNDNPC19gkMlPAfAf41yWlkGztXMIvUQrX9XWZFQRw7abhH3nks+XZGQpybINAxT2pKdFew==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.68.3.tgz", + "integrity": "sha512-xo5xeo/AjEB/ArzQjGn0JRDZuybZicQ5O3VPfko6ocH1li/qNrN4p5+R/WgjavzRz6UwAOaqsau7VvRQA6i6AA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.68.3.tgz", + "integrity": "sha512-zdckkcxHDEEKyDbC1t21DeaaiKGymxbkBU9c3zyfaaz+8N96ItJw4nmzHhZF+Mukgt906fnf2tsc90pVyStuHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.68.3.tgz", + "integrity": "sha512-9oXqI7g/ycEz7TyicdGBC4sL6PfWMXAx8u15f/nd7lYkCLJd8U8VdBfbpc4SSnRBU/e7aPALve3mhzasGDeCYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.68.3.tgz", + "integrity": "sha512-hbgT4NlaOELE3D5UUzSqF+OFgwz4Scvo2SQD9nZJUFjdIsg9Kg3FabQauUxkHKY9N5yjNXfXRRmiKNN4JpLmFA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.68.3.tgz", + "integrity": "sha512-yECcXZ/Bl+JVRhLFgld42rYrXgPdE0LtySGAmmmH6OtkaJM17A4cWG/eCzDymMVb52/jZjW0R54YrTHj4xXlSA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.68.3.tgz", + "integrity": "sha512-q4Q4/B7wyqM+TFqY5tJYQlaz5+ksGopcRmMeMdu4q6eaPK7N1PymTjIaH5LL32mMJBqIzpRof7BhlYLim5JgNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.68.3.tgz", + "integrity": "sha512-Ich3TGl/7GqhQ6G6jVPzgGQGJjd3E5hECxSVanPYchy6Vwcq+WI8wG/gmEMilHNy+ZYCR6U8EN50EejG3TaIgw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.68.3.tgz", + "integrity": "sha512-URBmOhwv4Y0Hi5Hhxc3cmqZLtQlx55DOs5PUhhITDC3zu0qwAfhcNAFAIwAhOUdA6NFVEck07CNZX6cBEs1vTg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.68.3.tgz", + "integrity": "sha512-PTdJXuZplRyaE3ECArlbZubI2LlUHWm0oCipCexnE/8LM+L7qIqUiNbU0piBxt46EB5zxXX+cpmDvHX4Z3WwcQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.68.3.tgz", + "integrity": "sha512-IlSQPDExSm9YdtrWeZIHj87GPXI9lYygRvHVwQ1o9t91JHIiB2CihrvNIASpc/zI28atqm04jS3proaQuaJMww==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.68.3.tgz", + "integrity": "sha512-O2ssyDcBTZkH5v2P/9ZaXJreL0hCKvUA5UwuHn0jCKeMLKi4GhspZJ1I5FT5QsHtJ/dPx4pup7pg/Lw0emeY0Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.68.3.tgz", + "integrity": "sha512-fesqagxcnc87lH2+aBWne/tFCmQVIGH+YezjY1wQwbUODuTBBlhHoyxju6umwn8LnjHVanjpoeaQdLsXP8JQSQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.68.3.tgz", + "integrity": "sha512-WAjFDtLW3HjJ2RAytKoWdFwlK/hW8rJHrjhRZFw14nR+c9JN//WIlSBkyXUjEYCNOFs2sGLNutOEPQG4iVYHgA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.68.3.tgz", + "integrity": "sha512-+fZiTeHV/1fy/14dRqE4thjYwUOABL6qQjxElOEQg2oHLkCamO8dxhHphVgD4+pFxtVEUIWxsGVduPtwnAlvbg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.68.3.tgz", + "integrity": "sha512-pfn4Zd9Ic3lEaSwW3GsQhTIDd7929C+eiEkOutsSCT2IHD6rDLblwmMQkgeGOso0oDo9Jk/ERtFdtFr9ElLs+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.68.3.tgz", + "integrity": "sha512-eUXzaeNQbKXKNqseL3g/usUqOPmRu+DbQsvwr9MXMdV+VQFUNb9bcWSNAAs/TRV95PCbFK46kLzHEOhFSzujsg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.68.3.tgz", + "integrity": "sha512-OiUclE7QDU4H/hr3ACRHhVGKWl+gNx+6Emignfq0hmNmzzTkZnT79wzB9NXKd0QH16S4t/wVqlAFBfC17nkZ5A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.68.3.tgz", + "integrity": "sha512-s6EclDWmk6zvIfk1yixgYthk7xHNx0xu5cEF5RDpS4IHNTpfswRX6xOXVG5cHF5xWn0B6EpDGARhPQ520KTlsA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.68.3.tgz", + "integrity": "sha512-G2xnmxGnU8XHLwtjnnXNRcLrub+Af3nm9VQ1QzL2aEiAL7woBdRgTCZBslJl8umA+YMqdEFpUh9kJB/Vyzk2wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.68.3.tgz", + "integrity": "sha512-Y/4tApNVrMUYWbAHsyRWJgwuuJOfhTNhA2B04Xpa6+G9btkPZ9kU3XagUKzPTwF3hg36NpQk748JsnoTVho67Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.68.3.tgz", + "integrity": "sha512-i2vH/OA5BcW+TdNg12ZTRC4rn+vILaPMP9CvHqnv+QEpMjBHGGNLo4k4EnEqzjYvTD6x1Xark9WhsQbH4bTzUQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.68.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.68.3.tgz", + "integrity": "sha512-ADb1Uz2MNM0sxVpAlMNdQG16Hw4sgW1aqVL7NeqBMpcZeiHb192d7W6shZdMQs33D+w9ihDYBBPsYqqc4MlD8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tauri-apps/api": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.12.4.tgz", + "integrity": "sha512-pVmfis+4zT8H0Qhp3xPZx9Ju7kpzvA6rr/PSJPyuwfvucTQ8sVt61NYU9KMkK703UFlYadFmjKA4HhybOtN0gg==", + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.12.4.tgz", + "integrity": "sha512-JI9bHfudSRJikGOrjbXEm6RjzzvmKuLc+JixB1NE8hNzQkNlCCIC3pTES3uypkR9lxHrsbxzcnSwhI2IxBQphw==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.12.4", + "@tauri-apps/cli-darwin-x64": "2.12.4", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.12.4", + "@tauri-apps/cli-linux-arm64-gnu": "2.12.4", + "@tauri-apps/cli-linux-arm64-musl": "2.12.4", + "@tauri-apps/cli-linux-riscv64-gnu": "2.12.4", + "@tauri-apps/cli-linux-x64-gnu": "2.12.4", + "@tauri-apps/cli-linux-x64-musl": "2.12.4", + "@tauri-apps/cli-win32-arm64-msvc": "2.12.4", + "@tauri-apps/cli-win32-ia32-msvc": "2.12.4", + "@tauri-apps/cli-win32-x64-msvc": "2.12.4" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.12.4.tgz", + "integrity": "sha512-OxqKSckIkoJ6vX2AjifIJpTasFC0Hbdoo7gEiCmAjauABO3U8m2MRsLWe+QTiBwDx1mIrvgA+rvI7tvDnbnHVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.12.4.tgz", + "integrity": "sha512-fz76/77wMMJOaaUN6n3CybRG0P/MTEjjqYk81mGPyhi9m6Ue5T+LWBnJP/AkPooNatBPI2vtulGqomyMJ44lCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.12.4.tgz", + "integrity": "sha512-K0w8Bof6Lt8QKLAYhRy0yy36ZH5iA/35VuSOvnxyjvCUZ+A3JKsUTlALviH/sVgAlisaPzzmeJSH8XOn4Q2HBA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.12.4.tgz", + "integrity": "sha512-j5rOnjmRUwWrm1oosf0zBYl4D+fqydgUROFCk0hvKZxvbTT8SOERes0QB7rBV/XWNy+kM6pCKzb3oSm2sRglzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.12.4.tgz", + "integrity": "sha512-aOue3Fy6Jb7+oWcfAVUsVHfeTybSCt2CZoU06aO4jv4d2Ks/KnaTPwMAK3CLEduGOvBLY1lbBBrIyomqLLH5Sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.12.4.tgz", + "integrity": "sha512-Fx6GShY/RvST+t6LMlTHAwd66+1tEaAAGrnU7cysVfaiRP1BKng5Vl6rVmO6rSLOA1Sp1dRzNYM4f0OWQGb7qA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.12.4.tgz", + "integrity": "sha512-tNzZSa79Z1nRpHxEpQ38lsAFpKlFlYvoXzjTV+lRRn/zSf3wrdUC3wnLcq2XEadchPu4ttK0zivhYzr+XGD19Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.12.4.tgz", + "integrity": "sha512-jmZ1pr0xEqUhuEusWtt9Yt+GF6lCnGHUmIL+KIknpbjK/XQ2qkhDBhaxK/JMHM2A8dAacVXCxXJk2EXpwhQUfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.12.4.tgz", + "integrity": "sha512-fGo8pgEHZxdSYgZ/J98m1usJ7NHKmKbq7k6uT0x1rpOq6Bg2YVzzpaAblWk710f5LHYBJIL5QIFS5IrD+4gmTg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.12.4.tgz", + "integrity": "sha512-ezl8sQIcjYsye3TUnTH5VcWmWzccZASlQm7hlZt0dYyj1XD0qpVW47u2xYVrIKui0F8uQv/7QGZixdWiClBsbg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.12.4.tgz", + "integrity": "sha512-DJhDeCqjLDNMWYFy7ZS8cfeAHX2RK0RbQMLiA3bMVVkXRDJ4NBYiHriGqsUhsr9iG41aTb+dJGkFPmPw1gWwVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/plugin-dialog": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.8.4.tgz", + "integrity": "sha512-+6ZOiXenOaxXwb8qCbBPdT2jX2cFPaVVHGIskrpmJLpmWj+qKRTD6X/z9x7hTdSQn7NedcoXCkWGej4a7dC4lw==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.12.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-65Emv9fQiQQqphLlRkuQ5ypPsOmWPhtBGCMv61JDPEPMvsx+gzhGf74yw1a78xFKPj6zw4AgQICJoQv0vK9M2w==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz", + "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.12.tgz", + "integrity": "sha512-Qe/KWYhEiIIxGs7HrAAjMfShxKldx19SJtr5zu53f3afPsdZNz7HHtdTLXo/kqeiWNXVycI24kSnfzBYkTzpgw==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.9.tgz", + "integrity": "sha512-0sE1406XBYJGiqD3AusTl9ZqC//2mIXix51tbom25gDCA8ri4xnSZg28CaSE8Srl6FClqABUKfsn0qghgdepMA==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.10.tgz", + "integrity": "sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.27", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.27.tgz", + "integrity": "sha512-VenMRv/eKNrspX9v3H4dbmjsrnCOYdYBG3kxXKk3dG6X+urBGcj2Prww3xw1U5K4FV/mE4h5GbWd0szEKf+9ew==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", + "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "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/@vitejs/plugin-react": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz", + "integrity": "sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.5.tgz", + "integrity": "sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.5", + "@vitest/utils": "2.1.5", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.5.tgz", + "integrity": "sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.5", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.5.tgz", + "integrity": "sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.5", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.5.tgz", + "integrity": "sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.5", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.5.tgz", + "integrity": "sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.5.tgz", + "integrity": "sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.5.tgz", + "integrity": "sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.5", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/@vitest/pretty-format": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.5.tgz", + "integrity": "sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.45.tgz", + "integrity": "sha512-XGHJrM6ufZARAc/w+tyOswStw9tdKiqCKBScI4gGaNxD+aaGu/HQWgKJ+JItjRLPqenQ7iE7G8AJC7T5ew1p+g==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.12", + "@vue/shared": "3.5.45", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.2" + } + }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.45.tgz", + "integrity": "sha512-LbP2d19GSOYGPmvMBBCVJVlv7TKtjM1Cfeyu3cYia720pknZP+1cLX7H5MVatvruT6MuJhiPuNbQBW/MDn/EwA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.45", + "@vue/shared": "3.5.45" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.45.tgz", + "integrity": "sha512-MKFjb2UX0M/l/jhfzqMLrI8VM4pfvFKG3pqFZkSZFHRLtNld/O4RtUPZFWSwhro/14qP88UQEkWzHxAZAQ0tsw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.12", + "@vue/compiler-core": "3.5.45", + "@vue/compiler-dom": "3.5.45", + "@vue/compiler-ssr": "3.5.45", + "@vue/shared": "3.5.45", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.32", + "source-map-js": "^1.2.2" + } + }, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.45.tgz", + "integrity": "sha512-RF5sbZOfYz5AK00tOJUn2PwFXR2fS1u2HVzI8D9VF9rGAFxuGBqg2bB1kJ3ZHMprqSltXnT9MZE1IsqjSM8oew==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.45", + "@vue/shared": "3.5.45" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.45.tgz", + "integrity": "sha512-WqkyubNWpI4OYBOipSrjIssMdJO8K1i9Zts/Wm8Er10/0msOEwCyWWWvZnAI7WW3kQsTong6DJp8Cbb+vd4cPA==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.45" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.45.tgz", + "integrity": "sha512-bzIO3+FABjpj85uIKSc+Qnj36/sxDNI3tcH9i6w6xKA1k6e0ejv0G0jMCfeJBvK3yGL5XbJ3DMZj+ClqyCHFYw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.45", + "@vue/shared": "3.5.45" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.45.tgz", + "integrity": "sha512-ZvRTFMDgfqTDYWvJfoVpQTJx1RN5M6l7Pyd6wfdY2NaXzbPQVh9ezeQYFbNPP6bIcRVn2SqSSR25N/jSW69BFw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.45", + "@vue/runtime-core": "3.5.45", + "@vue/shared": "3.5.45", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.45.tgz", + "integrity": "sha512-1fNXUHhhsWf4EVL4XixbGBU5mKdiIXJAB82feHRTyPPo6ZUEYWIJuEeUl3mVV6QDBp50HJOX4obLhxYXlrjrzA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.45", + "@vue/runtime-dom": "3.5.45", + "@vue/shared": "3.5.45" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.45.tgz", + "integrity": "sha512-ue9fgHmVNPlP7iW3+cxoBX/Cnlw53dHlVSw0JKGY6z1lObg8pHoj928M2nzG4/yVsMZ3NaRZ2s2z61uC16NDwQ==", + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.37", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.37.tgz", + "integrity": "sha512-QYph+vfurmaxhNwi9FprfmtkT5cx2Keg8FzZ0vnjO8ukscIybVyZGMFwdllKGlTI6qyU8ck43OM9UXh+IFJihQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.29.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.5.tgz", + "integrity": "sha512-khTmKu5NGYTotqcYo8Bew2k4RAE9PuXRSFRXG2lQBrCEQHyeQ/vX6gKMxfokwywBsLiXZMnHsmWMG1pnO8J7uQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.33", + "caniuse-lite": "^1.0.30001819", + "electron-to-chromium": "^1.5.464", + "node-releases": "^2.0.60", + "update-browserslist-db": "^1.3.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001826", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001826.tgz", + "integrity": "sha512-wTB+9tIbLro/BCXwLuNV1meHE4L9dS6dArMDwgYfNBPMYScqClHyGunhkCSDtHhe/69Xl0sHlKgBVZ+fNsYtWA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chevrotain": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-13.2.0.tgz", + "integrity": "sha512-GTouk5YzgBxlTPCaDn5q0q2EJKkrYmnPF+HmF8v0Qo4r3iyPG7HJivkN1wthCXZcm3sIcZFpGTRovLPNdJNRCA==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "13.2.0", + "@chevrotain/gast": "13.2.0", + "@chevrotain/regexp-to-ast": "13.2.0", + "@chevrotain/types": "13.2.0", + "@chevrotain/utils": "13.2.0" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/codemirror": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", + "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/crelt": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz", + "integrity": "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==", + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/cytoscape": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.35.0.tgz", + "integrity": "sha512-sMvBIXiGMnhkCaWz2R06FwF/27MNlS+Tqvi17foO9UhnUg3XGZccKjxsvEqQFAQYMSSZmN5SxYzUYlQ0DOJJ3g==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.2.tgz", + "integrity": "sha512-ZKb/mONPVKzaO5UlcWcwN8bS4ezvQaYu+bsou+XgNABdGC800kwH651ADTbbTxMPHW13UlvbQafdmJQDk1w7Mg==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.5", + "d3-axis": "^3.0.1", + "d3-brush": "^3.0.1", + "d3-chord": "^3.0.2", + "d3-color": "^3.1.1", + "d3-contour": "^4.0.3", + "d3-delaunay": "^6.0.6", + "d3-dispatch": "^3.0.2", + "d3-drag": "^3.0.1", + "d3-dsv": "^3.0.2", + "d3-ease": "^3.0.2", + "d3-fetch": "^3.0.2", + "d3-force": "^3.0.1", + "d3-format": "^3.1.3", + "d3-geo": "^3.1.2", + "d3-hierarchy": "^3.1.3", + "d3-interpolate": "^3.0.2", + "d3-path": "^3.1.1", + "d3-polygon": "^3.0.2", + "d3-quadtree": "^3.0.2", + "d3-random": "^3.0.2", + "d3-scale": "^4.0.3", + "d3-scale-chromatic": "^3.1.1", + "d3-selection": "^3.0.1", + "d3-shape": "^3.2.1", + "d3-time": "^3.1.1", + "d3-time-format": "^4.1.1", + "d3-timer": "^3.0.2", + "d3-transition": "^3.0.2", + "d3-zoom": "^3.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.5.tgz", + "integrity": "sha512-Th8qGXoBalmWsstpkuhmBuTsBQIFqYOJtjlBvNVvBfJ8E3uYusBUwUR8HU20U0qKKQkgCvKyR1YjiozWadk5QA==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.1.tgz", + "integrity": "sha512-E5QCXfaf/uJZEHHiqoWRq+bQEm2PzoVFv2rDC7CZ3wwI0MjfMW3w83J3ubobG4IJj3lShAI5eiPJhOu/8wHofA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.1.tgz", + "integrity": "sha512-L5Glqa/Gb7LU3ndIOMtA5mDzlJ0aXKp5ELP2X09ctWF23jO7+faIUVDbmaIi+D6k3EemXFWn1F3lkfguExoVhA==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.2.tgz", + "integrity": "sha512-cGmADo5M2PTi3ewJZ2lcE32eURd4JmHtQ5JwRIUcas5L1SXqufG9yPyjWp8fW0gRi7aZi9bgbZPFZO1eyZ+1CQ==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.1.tgz", + "integrity": "sha512-lfab8x0Bj0UO7SNsY8dZSbNIA6ipbkE3X0NG9nqjCu6CfCHZseuDnOSJY7hidKrjpP++i1M2qT+FlAdPKYRilA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.3.tgz", + "integrity": "sha512-5DYURc8KwXPOhSUBblU0P9rVcArsSPxPOxsfO0Eud0s28oU0sB2e80aRHRL9AZW3usT8ikFKyIHpHHLNWLdRVA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.6.tgz", + "integrity": "sha512-DMQIEvSJhZCB6pwedcXaAlQ+MeKU5LlM2XakKtc73b/VM+RBiI1SRXycOEOKg2jsKj4zZ9F0KGYG6nCGwwWu/g==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.2.tgz", + "integrity": "sha512-sAzH4Y4nsLo8eSqw5jKiZt+LU2wZmL/qS+OkxQGjhwazB/D7TY34R/QK1eshfGr7cZEKymKZ/Haem7m+lu98Sg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.1.tgz", + "integrity": "sha512-OWeoayCq8J69hUIjvL+Mb6Q6Oaj/fyHV5XaXByEUAG+JUjIfTGDnk3qGpcXrD3VmQ3BSV96fcbM6fqq7C0tbPA==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.2.tgz", + "integrity": "sha512-FUnXhX7I4/AXyRCZzwfZTDGSq8PGZ4oR0tiCBqNGOZMsDrQ+6sIWNQnBzcCGhzJKZ6uCvCezTwflUqI209RRiQ==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-B5znKqRmKROAN4oHWQ50W/qisVjA9GXh2WMsVKdFVp4DxWmcrOsweqgUOUVsv5th96kwaZlokU6SlV4J3gak1w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.2.tgz", + "integrity": "sha512-1wGF62bgjMRbF6mqbD+6rRWBL2hwWVYQjFO2UP3Wm1nIAvJZKaQxXM5caVY7athoCa8wIq9lCf7g44lPWFk50g==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.1.tgz", + "integrity": "sha512-kAaaHLFebBYwgi5cYBXAI8vKrQFMCD2MEswj2QuPKKbdU1wYLc8WXtS7O8F/b6POCIe3gJjY6hkDstHi1yMETQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.3.tgz", + "integrity": "sha512-+F+/49swqmGuQJmSKnVMIDH/QkEFV5li9QRj0xm/KhyAUBv099O5PrvpQFxBp24PYph17Mnvt9mjKQV0ii0nMA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.2.tgz", + "integrity": "sha512-5R8ZgDQorIxmauv7R6gpE/ndz+Z0qAZssigq0aXFdvPHdY41RqtW02jrRUQAL724NdPABYXo1+gQEGBBr7uKNg==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.3.tgz", + "integrity": "sha512-GRajN5ZcnEwYFWqqdzhG1qJ3+fDg6WWzk47TJg7ePY7yvYAgRfD2r1mUx+wviBOWuCwamCUzjwMSdato43jbGA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.2.tgz", + "integrity": "sha512-IRzGU62DtxhvsnSTWMQIdnoZ6gA+BCWwBon1EJI6SjoN595799b6z/QRBzXfFhE8iupUPp3042yBNo0STPqnzQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-jsbgV8zIT38ReB9O7X7gcLndTQRONSqNNd+oGIaTBdUug4r5jFmp0N6RY9R5GWbdUDucn0qoTGyfjapT4tDhcg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-WAUvPudGU1Dn4mDPfb6+JnnbeVEV53hG/BoT+bxts6AkZsOpTEiV1jHYX+2vtwCICNFG9Wxv8QS+eW1zE/Dwfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.2.tgz", + "integrity": "sha512-9Lu9mqJKRbIk0d6mKDjpvPURaPdwHVK5CYbcdd0/4vBgz4ldz/7TIOse3kNERsByGNfld58KEco507AztJWyTQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.2.tgz", + "integrity": "sha512-PxJi9LNV+7mulaYO77nd+oGurXGL1fhedXjHnB3pWLUcqDnQtF4VASoqnQGHgoXLByVdv5QJ/2kfwkGn5HTS8g==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.3.tgz", + "integrity": "sha512-66cWobCNzcMvlfoaDHCxuIv9TBUWG1BLOWdv9kHHFuCr1JdqAWPvTmsaEYDD5NRMyWZ5+7u0GqiCDfMXMqh3hg==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.1.tgz", + "integrity": "sha512-lA5gfN2yMvmChubmptnDiBfeGpHD7Yb1EbvCz0TZE0WHXhyR6W2allPuhKtzV5ILQRqeOdefF0qYtERReLUBDg==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-scale": "1 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.1.tgz", + "integrity": "sha512-ODSf35vqCrlCfp7hrm0eZjvOosSXSYLjqvIlhMBV9q9VOx7EBJG6pc+uXBswEZNJgCGJ+qnKYcWutbZDIxe/Xg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.1.tgz", + "integrity": "sha512-dm2o+lbKdzg9tY7GEag/dB9hcbodLfwkE/DkvqbELJXaMz0yKzWWhZqhbI7CKubukA7HnRyz0avdtvi7EPxPvw==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.1.tgz", + "integrity": "sha512-Ze7rjrhMzdeulh0/hjcfFj7XLAHOfowtEMfsoG6DU866HPynQNW7Wfen6hzXcqKTv8XzxvF6Hzr5XD6bMHr2ug==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.1.tgz", + "integrity": "sha512-22XaqjyCjpqgda20erhsOjGmC3vvYwTNYniKAd45W5UWLDF43moeOuV9qYpRqobIlsnK0UhnKZjUUJm3VgORUA==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-1Il1aliroVSErrv5aulRBxAY+7+DnaoLIWGd1C6SsBTWDeobWiP/V69vwb8vT6abR1kKwaNe1196pmaQ1fK90A==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.2.tgz", + "integrity": "sha512-RcjCsdFgyFoDB+QXLC5m60ZkTN0k9zH+ovoLlTdJnDS1AbfbcuowiM4pCKSTOclNibS4f4J4cbv2m7O7y8NTOQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.1.tgz", + "integrity": "sha512-kfjD3BDQu/FOatpZ6JdMSyIoDwTxIpI29ySTI2J5ZlDaH1WbuJGQJ2Q9oJkWTEZEW98j6idezoomSD3Cn2zwiw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "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", + "lodash-es": "^4.17.21" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/dayjs": { + "version": "1.11.23", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/delaunator": { + "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/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dompurify": { + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.17.tgz", + "integrity": "sha512-B/pSlYVHQ58kqISD/yDjuJ1yfzI34m1gF4lAod2bwSRhiN4K5Cl3H8Af7hqB2PmTL911tdEudnnXn5FnhRoz0w==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.485", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.485.tgz", + "integrity": "sha512-m3uadzR0Z+sR19HGWgfxoZcKv9hE/edVM9OZ+FJ4wNRyfuFtkwZJIDoehEty5sisYVwmge8lKV1tenWOyClVgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/elkjs": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.12.1.tgz", + "integrity": "sha512-IhMYKHE4S2vtx0QrhBP3lYOIKDeIiJXBrdq9MGYkuB8ZHqhrBnHNfSUndjXFewrX1CPK8chwq+2NA0K0hliYuw==", + "license": "EPL-2.0 OR GPL-3.0-or-later" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-toolkit": { + "version": "1.53.2", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.53.2.tgz", + "integrity": "sha512-iUqZ+NlwH4jUgRmXZUxFBsV/9762TQEa1O4IXLFBmDEjVHScBytKuseX23I0+v9ShZ5MYxEx6WKNzm6IPnex8g==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks", + "tests/types", + "tests/browser-compat" + ] + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/katex": { + "version": "0.16.11", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", + "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "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/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-table": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.1.0.tgz", + "integrity": "sha512-xpeSCdM+B+6P3ncfgaB7FoDbtJ30xAe6Z18TGT7AgXJsHqCElCICZovQqdRMm7kHgpTyYv36EupqewoFFSB8vw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-definitions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.4.tgz", + "integrity": "sha512-z4B5c6jrnJ1ltOQemhWYPBSAo6y42Z8Gt2yEgfgNTMcLSU59B8bfj8Z8AnAlJrBGLnqkdAUZ7jdDEqQw3KuipQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.1.0.tgz", + "integrity": "sha512-KRLgmPaP2H1ul2bpoJkOS+9pAcDAAj9Nu1mqLnh8NLeJG5tlvj42TH80PIGBpROWlRXLk0lDrWNuZCFy/tsB4A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-Jx6QSK8wDo558Bcf7q+1pe0v81g2PVs09Hlvu9xJHmCFRF3sAPW7vXFVIAwBncs3sde92WbsVqNxwdqViA2XnQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.1.tgz", + "integrity": "sha512-OuJHqvr455pwu2OaOrir7dbzqs4jlWKOtlu9L6GjcIjjQwNyw02VntQsr/Ek6/A13vgnXfUhBekWRUP1OkNivw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.1.tgz", + "integrity": "sha512-fiIjPrAy4kz68/eFbPHhsiWDGHhqUSVoU1XsfLM5DsEPXw7MxgiVVyulUggFRckVWeT1KXQXkg5vm3kv4oMSOA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "mdast-util-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.1.tgz", + "integrity": "sha512-jXVO1hvB2hs82g1esi7I9nIJDqiijbQLIyH2jDUb5s7jIAZMr/79h0VHSq7XHKTqpLARRm+DDNjduB7S9+6XZA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-math": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "longest-streak": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.1.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.2.3.tgz", + "integrity": "sha512-dImdB6VZRMRac1SwAW6o1c0ESk/7pFFAMCMuKM+9v7LpTSthMM5nzXpqKw4Mjo66aXVKhNkyrP4bMB9MurPyWg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mermaid": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-12.3.0.tgz", + "integrity": "sha512-4113TdXeLAsMruJ79OpFL5O8+LTFXhQqZ260rF3tgUmiNAtRm4Uume04I+65PRN6yZ69J4f8rVYWW8zRk65UYw==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.2", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^2.0.1", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "chevrotain": "~13.2.0", + "cytoscape": "^3.34.0", + "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.14", + "dayjs": "^1.11.21", + "dompurify": "^3.4.17", + "elkjs": "^0.12.0", + "es-toolkit": "^1.45.1", + "katex": "^0.18.0", + "khroma": "^2.1.0", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/mermaid/node_modules/commander": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.1.0.tgz", + "integrity": "sha512-cgnQ88TRrWcC7pVq46RzJVRMktu3W2RcbnoidnfBsl1bmDCBwJS/udcIZpKoCrbAYYaCqsz1yZCVIgbIaU3ddQ==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/mermaid/node_modules/katex": { + "version": "0.18.10", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.18.10.tgz", + "integrity": "sha512-/B6p9eY9DX7aHBfpkHdpirDTZ5QH9xTwL9y837PWuzuv41O5jFdqNQwVQEQsimY0/iVNkwBY4+4hMfhQ7d4Dbw==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^15.0.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/micromark": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.3.tgz", + "integrity": "sha512-oGYfQzHSG5dOMovQcJ3fyTmZlWAWpi0XA0sJwJs+i6OT88o1+Jtw/8z0CmdowSLxGhhFK89rQ/oXph/wN02PNw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.4.tgz", + "integrity": "sha512-wxEeE8v8XVvOrxn1TZj74qYhAtTQsSqufHVS3uNVyT1MupXxhyaHk8/9xDNPh9BmL77QNDgWTkZ3RsYHB2ry7w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.1.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.3" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.2.tgz", + "integrity": "sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.1.0.tgz", + "integrity": "sha512-fS8hnLIjnjvdQIj39Geug8wWsR0HrYZ43KShKxNfwT7t2LOHo/LbWZEzEaSOjwtjdCsjoE6syHhonEzW0zv0+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-edit-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-edit-map/-/micromark-util-edit-map-1.0.0.tgz", + "integrity": "sha512-Pa2ljlsEL6sVwFaYeyrOLSYbQt73JvGbPOYFq+9AElXiSnfI5Q4465RRZ1sHv7lDjDOnGRDDaqPXqClqWK/q1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-6.0.2.tgz", + "integrity": "sha512-hIvVOb9Qr1p/9CNNLOe0OlWvgx/ziTsVwKN/GDSsuArN2K0wDiafP3s0SWmsm7o2BdnyS8Z9Z64NFBUbn6ziBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^22 || ^24 || >=26" + } + }, + "node_modules/node-releases": { + "version": "2.0.64", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.64.tgz", + "integrity": "sha512-zAPCKqMcnqs2nGy6nlkm7JduFseiBJy3EXHGLh+8pFR+TxGCBxxiEN21+UROU5CKwX/f4TlUcYjiM+vs/tsyxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nwsapi": { + "version": "2.2.28", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.28.tgz", + "integrity": "sha512-IlVB7OS7qrOsVYlpnFIkETjMwT9jwvmocJmmM+GZU/PAB3uGi9Ezd7vcWhWBUnSc0ya4ppmQITOyP1ez9gg8cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "license": "MIT" + }, + "node_modules/package-manager-detector": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.9.0.tgz", + "integrity": "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/postcss": { + "version": "8.5.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.32.tgz", + "integrity": "sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/prosemirror-changeset": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.6.tgz", + "integrity": "sha512-P0cY3DSLm4M2boUOCmHDyaID5o6HgWmb21Bvs9p8lLqfJjKBBEHG5Ma5qW5SCmwOYamtWOLf2k+yvt6077zlTg==", + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.2.tgz", + "integrity": "sha512-q6Q6szxqdu9Xd6EcdKsqXghu5nQdZTpB4Q9yd04WRc7/jt763e/rT60Owh0L1GYY+T46o5rD+9lEN36dZS43tw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-drop-indicator": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/prosemirror-drop-indicator/-/prosemirror-drop-indicator-0.1.4.tgz", + "integrity": "sha512-YaRB1pZmU5GCorPVWbc9dbhbwqr4iMBO/AjPu4BTKHCUzxEDUXje2dUyoxOHib/z4uyPUZTJz64h7mHDJZeSzA==", + "license": "MIT", + "dependencies": { + "@ocavue/utils": "^1.6.0", + "prosemirror-model": "^1.25.7", + "prosemirror-state": "^1.4.4", + "prosemirror-view": "^1.41.8" + }, + "funding": { + "url": "https://github.com/sponsors/ocavue" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.4.tgz", + "integrity": "sha512-VmKxhcA6a+h5oPSYmfF1ZNeQqPbyYaIxqZsKqeYCyTlPtrjUgNaHL3P8vVaO19oqAV0zuaM/axkowZHrB1P3Tg==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.1.tgz", + "integrity": "sha512-onlwnqKvgtFg6srZOmDOAhlAy1FIHQpOExORybX0S+DvJepE5tPALrB9iGet/2sqqqrelSnB10OoiOJqAvu2DA==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.6.0.tgz", + "integrity": "sha512-e/Ukf5qy6Pq49l7M7/ObOQThIyBR2Is5g2qJq4e6LXKuCGr66/Rr4MjghkL3kB5ty4MOG92P8LyqwC5ET7Qx7g==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.13", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.13.tgz", + "integrity": "sha512-MlDMWGjYXaYOeCiO17jcybntCOzPnN+97U0809ke2QsgPtxW3n5/sD6ZKyJONUgMw1iP93ohZTjeKjnRJ7L6kQ==", + "license": "MIT", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-safari-ime-span": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/prosemirror-safari-ime-span/-/prosemirror-safari-ime-span-1.0.2.tgz", + "integrity": "sha512-QJqD8s1zE/CuK56kDsUhndh5hiHh/gFnAuPOA9ytva2s85/ZEt2tNWeALTJN48DtWghSKOmiBsvVn2OlnJ5H2w==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.4.3", + "prosemirror-view": "^1.33.8" + }, + "funding": { + "url": "https://github.com/sponsors/ocavue" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.6.0.tgz", + "integrity": "sha512-G1srDtan+VqWn+qpmWFj/6j0YsZ5zMU+ZIlGVIW41a5JF2jAI3jzfMRWmSABmEH2Qoq1PmAG/o2mucMMdLOsLg==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.12.5", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.5.tgz", + "integrity": "sha512-3EBXZBM4h3MKuWvs9sQ7IA0/v6jCqCZ4wC08PIvzY1VSQWDL90KEyfg5C0Ex52UJesf/QVogxvuBsZdKmLc3NQ==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.42.9", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.9.tgz", + "integrity": "sha512-bKbfzeKZOu2H2JQU2TaJmYu6EBcor3VnGIR4jR31cbEt1ztUnfUB6bKGV1+fJzOJdrVWR+tRU0208zM3oQx4wA==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.25.12", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remark": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", + "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-inline-links": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/remark-inline-links/-/remark-inline-links-7.0.0.tgz", + "integrity": "sha512-4uj1pPM+F495ySZhTIB6ay2oSkTsKgmYaKk/q5HIdhX2fuyLEegpjWa0VdJRJ01sgOqAFo7MBKdDUejIYBMVMQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-definitions": "^6.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-math": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", + "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-math": "^3.0.0", + "micromark-extension-math": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/robust-predicates": { + "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.68.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.68.3.tgz", + "integrity": "sha512-wd2gavj7CEQv52rdcVqfUupO/KPIKcoJKxyFWl4cOqYZGMQEOSijJRkliz0dRa7gpkj/h4TRqyWa+dJJi6T0OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.10" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.68.3", + "@rollup/rollup-android-arm64": "4.68.3", + "@rollup/rollup-android-x64": "4.68.3", + "@rollup/rollup-darwin-arm64": "4.68.3", + "@rollup/rollup-darwin-x64": "4.68.3", + "@rollup/rollup-freebsd-arm64": "4.68.3", + "@rollup/rollup-freebsd-x64": "4.68.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.68.3", + "@rollup/rollup-linux-arm-musleabihf": "4.68.3", + "@rollup/rollup-linux-arm64-gnu": "4.68.3", + "@rollup/rollup-linux-arm64-musl": "4.68.3", + "@rollup/rollup-linux-loong64-gnu": "4.68.3", + "@rollup/rollup-linux-loong64-musl": "4.68.3", + "@rollup/rollup-linux-ppc64-gnu": "4.68.3", + "@rollup/rollup-linux-ppc64-musl": "4.68.3", + "@rollup/rollup-linux-riscv64-gnu": "4.68.3", + "@rollup/rollup-linux-riscv64-musl": "4.68.3", + "@rollup/rollup-linux-s390x-gnu": "4.68.3", + "@rollup/rollup-linux-x64-gnu": "4.68.3", + "@rollup/rollup-linux-x64-musl": "4.68.3", + "@rollup/rollup-openbsd-x64": "4.68.3", + "@rollup/rollup-openharmony-arm64": "4.68.3", + "@rollup/rollup-win32-arm64-msvc": "4.68.3", + "@rollup/rollup-win32-ia32-msvc": "4.68.3", + "@rollup/rollup-win32-x64-gnu": "4.68.3", + "@rollup/rollup-win32-x64-msvc": "4.68.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "license": "MIT" + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.2.tgz", + "integrity": "sha512-GYrCADwpu6yV5OAvchkQ27Z5wwMxWAEMg5NNWjyHh/5DboFFqbdbvYNIvZouQpxXyeMPoTOh0vdPYKlf0ZswdQ==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/style-mod": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.4.tgz", + "integrity": "sha512-XXWIQt633/EpAFx8aZDOTjBzrCaGmhvEQlQo6MVPfa2OzO2cWo+4hV9h+6UkHYlXGfy+ODXKUdP7Pthmcu5ATw==", + "license": "MIT" + }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "license": "MIT" + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-dedent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.2.0.tgz", + "integrity": "sha512-fpsYs/VVoZxfGY9/j3FQpZmN8wdLJaV1Pt38AaJNZu9uKIHcFU3halCdBveEq1HGKO1OEfJY65w1zvoFV1b3qQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.1.0.tgz", + "integrity": "sha512-vKXxz6O38sKDj1mtx/k2cWvkkFBuYGx6uGrlzBkVeWCRF/F8sdI0j3Wbkz/5rVNRRuVc8UrgRdbCxNhmYXgP3w==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz", + "integrity": "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.4.tgz", + "integrity": "sha512-66ycRswIkNmHH9PHku7ADtv5RVwgIrOcuv3J8Svz6h4qgGRrKVa+9/neuKyJZUXyOpYwLTvS+whZ4R2urHHgQg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.5.tgz", + "integrity": "sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.5.tgz", + "integrity": "sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.5", + "@vitest/mocker": "2.1.5", + "@vitest/pretty-format": "^2.1.5", + "@vitest/runner": "2.1.5", + "@vitest/snapshot": "2.1.5", + "@vitest/spy": "2.1.5", + "@vitest/utils": "2.1.5", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.5", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.5", + "@vitest/ui": "2.1.5", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.45", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.45.tgz", + "integrity": "sha512-3cvsib8m9c0vB24+MDKsgcW4+Da4xaBl9Z/5Tbm2pmSIsRPxcil4cdXjXlVsmJ2g64XJo5h+IRd7rsdGT9pZaw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.45", + "@vue/compiler-sfc": "3.5.45", + "@vue/runtime-dom": "3.5.45", + "@vue/server-renderer": "3.5.45", + "@vue/shared": "3.5.45" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.23.0.tgz", + "integrity": "sha512-wCkmX8QMOrKjgO8HW2WyDbTSGeqkocxgDzS9iR79rEAexty6/2qzilx3Ag8Tqf9ykop3irLKle0MtVn5qjVnoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..4c00e61 --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "dependencies": { + "@milkdown/kit": "7.23.0", + "@tauri-apps/api": "^2.12.4", + "@tauri-apps/plugin-dialog": "^2.2.0", + "react": "18.3.1", + "react-dom": "18.3.1", + "codemirror": "6.0.2", + "@codemirror/lang-markdown": "6.5.2", + "@codemirror/language-data": "6.5.2", + "@codemirror/theme-one-dark": "6.1.3", + "@milkdown/plugin-math": "7.5.9", + "katex": "0.16.11", + "mermaid": "12.3.0" + }, + "devDependencies": { + "@tauri-apps/cli": "^2.2.0", + "@types/react": "18.3.11", + "@types/react-dom": "18.3.1", + "@vitejs/plugin-react": "4.3.3", + "jsdom": "25.0.1", + "typescript": "5.6.3", + "vite": "5.4.11", + "vitest": "2.1.5" + }, + "name": "new-markdown", + "private": true, + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "tauri": "tauri", + "test": "vitest run", + "typecheck": "tsc -b --pretty false" + }, + "type": "module", + "version": "0.1.0" +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..061e6d3 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,489 @@ +import { Suspense, lazy, useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react' +import type { Editor } from '@milkdown/kit/core' +import TitleBar from './components/TitleBar' +import MenuBar, { type MenuDef } from './components/MenuBar' +import TabBar from './components/TabBar' +import Sidebar from './components/Sidebar' +import StatusBar from './components/StatusBar' +import EditorPane from './components/EditorPane' +import type { SourceEditorApi } from './components/SourceEditor' +// 源码编辑器(CodeMirror)懒加载:不进首屏主包,仅切到源码模式时加载 +const SourceEditor = lazy(() => import('./components/SourceEditor')) +import { offsetInMarkdown, type CursorAnchor } from './editor/cursorSync' +import { insertPlainText, insertLinkText } from './editor/paste' +import { isImeComposing } from './utils/ime' +import { ConfirmSaveModal, AboutModal, ShortcutsModal, LinkModal, ErrorModal } from './components/Modals' +import { tabsReducer, createTab, activeTab, isDirty, type DocTab, type TabsState } from './stores/tabs' +import { countWords, countChars, extractOutline, baseName, type OutlineItem } from './utils/text' +import { callUndo, callRedo, focusEditor, type CursorInfo } from './editor/editor' +import { editorCommands, insertMermaidBlock, insertMathBlock } from './editor/commands' +import { + isTauri, pickOpenFile, pickSaveFile, pickFolder, readTextFile, writeTextFile, + pickAndReadWebFile, downloadTextFile, + pickImageFile, pickAnyFile, pickAndReadWebImage, copyToAssets, saveBytesToAssets, +} from './services/platform' + +const WELCOME_MD = `# 欢迎使用 new-markdown + +这是阶段 1 的桌面骨架:标题栏、菜单、标签页、侧边栏、状态栏与编辑器已经接通,**打开 → 编辑 → 保存**全链路可用。 + +## 现在可以试 + +- 文件菜单:新建、打开文件、打开文件夹、保存、另存为 +- 段落/格式菜单与快捷键:Ctrl+1~6 标题、Ctrl+B 加粗、Ctrl+Shift+Q 引用 +- 左侧大纲:点击标题定位;文件页签需要先打开文件夹 +- 视图菜单:源码模式、深色主题、侧边栏开关、缩放 + +试着输入 \`# \` 加空格,或 \`- [ ] \` 开始一个任务列表。 +` + +const RECENT_KEY = 'new-markdown:recent' +const UI_KEY = 'new-markdown:ui' + +function loadRecent(): string[] { + try { return JSON.parse(localStorage.getItem(RECENT_KEY) ?? '[]') as string[] } catch { return [] } +} +function loadUi(): { theme: 'light' | 'dark'; sidebar: boolean; sidebarWidth: number } { + try { + return { theme: 'light', sidebar: true, sidebarWidth: 250, ...JSON.parse(localStorage.getItem(UI_KEY) ?? '{}') } + } catch { return { theme: 'light', sidebar: true, sidebarWidth: 250 } } +} + +function toDiskContent(content: string, lineEnding: string): string { + return lineEnding === 'CRLF' ? content.replace(/\n/g, '\r\n') : content +} + +export default function App() { + const [state, dispatch] = useReducer(tabsReducer, undefined, (): TabsState => { + const welcome = createTab({ title: '欢迎', content: WELCOME_MD }) + return { tabs: [welcome], activeId: welcome.id } + }) + const tab = activeTab(state) + + const [workspaceRoot, setWorkspaceRoot] = useState(null) + const [sidebarMode, setSidebarMode] = useState<'files' | 'outline'>('outline') + const [recent, setRecent] = useState(loadRecent) + const [cursor, setCursor] = useState({ line: 1, col: 1 }) + const [sourceMode, setSourceMode] = useState(false) + const [editorEpoch, setEditorEpoch] = useState(0) + const [zoom, setZoom] = useState(1) + const [ui, setUi] = useState(loadUi) + const [modal, setModal] = useState<'about' | 'shortcuts' | 'link' | null>(null) + const [error, setError] = useState(null) + const [pendingClose, setPendingClose] = useState<{ ids: string[]; after: () => void } | null>(null) + + const editorRef = useRef(null) + const jumpRef = useRef<(text: string) => void>(() => undefined) + const anchorApiRef = useRef<{ getAnchor: () => CursorAnchor | null; setCursorByAnchor: (a: CursorAnchor) => void } | null>(null) + const sourceApiRef = useRef(null) + const pendingAnchorRef = useRef(null) + const [sourceCursorOffset, setSourceCursorOffset] = useState(0) + const tauriMode = isTauri() + + useEffect(() => { + document.documentElement.dataset.theme = ui.theme + localStorage.setItem(UI_KEY, JSON.stringify(ui)) + }, [ui]) + + useEffect(() => { + localStorage.setItem(RECENT_KEY, JSON.stringify(recent)) + }, [recent]) + + const pushRecent = useCallback((path: string) => { + setRecent((prev) => [path, ...prev.filter((p) => p !== path)].slice(0, 10)) + }, []) + + // ——— 文件动作 ——— + const openPath = useCallback(async (path: string) => { + try { + const file = await readTextFile(path) + dispatch({ + type: 'open', + tab: createTab({ + path, title: baseName(path), content: file.content, + encoding: file.encoding, lineEnding: file.lineEnding, hadBom: file.hadBom, + }), + }) + pushRecent(path) + } catch (e) { setError(String(e)) } + }, [pushRecent]) + + const newDoc = useCallback(() => { + dispatch({ type: 'open', tab: createTab({ title: '未命名', content: '' }) }) + setSourceMode(false) + }, []) + + const openFile = useCallback(async () => { + if (tauriMode) { + const path = await pickOpenFile() + if (path) await openPath(path) + } else { + const picked = await pickAndReadWebFile() + if (picked) { + dispatch({ type: 'open', tab: createTab({ title: picked.name.replace(/\.(md|markdown|txt)$/i, ''), content: picked.content }) }) + } + } + }, [tauriMode, openPath]) + + const openFolder = useCallback(async () => { + const folder = await pickFolder() + if (folder) { + setWorkspaceRoot(folder) + setSidebarMode('files') + setUi((u) => ({ ...u, sidebar: true })) + } + }, []) + + const saveTab = useCallback(async (target: DocTab, saveAs: boolean): Promise => { + try { + if (!tauriMode) { + downloadTextFile(`${target.title}.md`, target.content) + dispatch({ type: 'saved', id: target.id }) + return true + } + let path = target.path + if (!path || saveAs) { + path = await pickSaveFile(path ?? `${target.title}.md`) + if (!path) return false + } + await writeTextFile(path, toDiskContent(target.content, target.lineEnding), target.hadBom) + dispatch({ type: 'saved', id: target.id, path, title: baseName(path) }) + pushRecent(path) + return true + } catch (e) { + setError(String(e)) + return false + } + }, [tauriMode, pushRecent]) + + const requestClose = useCallback((ids: string[], after: () => void) => { + const dirtyOnes = state.tabs.filter((t) => ids.includes(t.id) && isDirty(t)) + if (dirtyOnes.length === 0) { after(); return } + setPendingClose({ ids, after }) + }, [state.tabs]) + + const closeTab = useCallback((id: string) => { + requestClose([id], () => dispatch({ type: 'close', id })) + }, [requestClose]) + + // ——— 编辑器动作 ——— + const withEditor = useCallback((fn: (e: Editor) => void) => { + if (editorRef.current) { fn(editorRef.current); focusEditor(editorRef.current) } + }, []) + + const toggleSourceMode = useCallback(() => { + if (!tab) return + if (!sourceMode) { + // 进入源码:把渲染光标锚点换算为源码偏移 + const anchor = anchorApiRef.current?.getAnchor() + setSourceCursorOffset(anchor ? offsetInMarkdown(tab.content, anchor) : 0) + setSourceMode(true) + } else { + // 退出源码:记住源码光标锚点,编辑器重建后回定位 + pendingAnchorRef.current = sourceApiRef.current?.getAnchor() ?? null + setSourceMode(false) + setEditorEpoch((n) => n + 1) // 以源码文本重建编辑器模型 + } + }, [tab, sourceMode]) + + const jumpHeading = useCallback((item: OutlineItem) => { + if (sourceMode) sourceApiRef.current?.jumpToLine(item.line) + else jumpRef.current(item.text) + }, [sourceMode]) + + // ——— 全局快捷键(编辑器内部快捷键如 Ctrl+B 由 Milkdown keymap 处理,菜单点击走命令) ——— + useEffect(() => { + const onKey = (e: KeyboardEvent) => { + if (isImeComposing(e)) return // IME 组合期间全局快捷键一律不触发(阶段 2 守卫) + const mod = e.ctrlKey || e.metaKey + if (!mod) return + const key = e.key.toLowerCase() + const inTextField = (e.target as HTMLElement)?.tagName === 'TEXTAREA' || (e.target as HTMLElement)?.tagName === 'INPUT' + if (key === 'n' && !inTextField) { e.preventDefault(); newDoc() } + else if (key === 'o' && !inTextField) { e.preventDefault(); void openFile() } + else if (key === 's' && tab) { e.preventDefault(); void saveTab(tab, e.shiftKey) } + else if (key === 'w' && tab) { e.preventDefault(); closeTab(tab.id) } + else if (key === 'l' && e.shiftKey) { e.preventDefault(); setUi((u) => ({ ...u, sidebar: !u.sidebar })) } + else if (key === 'k' && !e.shiftKey && !inTextField) { e.preventDefault(); setModal('link') } + else if (key === 't' && !e.shiftKey && !inTextField) { e.preventDefault(); withEditor((ed) => editorCommands.insertTable(ed)) } + else if (key === 'i' && e.shiftKey) { e.preventDefault(); void insertImage() } + else if (key === 'q' && e.shiftKey) { e.preventDefault(); withEditor(editorCommands.blockquote) } + else if (key === 'k' && e.shiftKey) { e.preventDefault(); withEditor(editorCommands.codeBlock) } + else if ((key === '=' || key === '+')) { e.preventDefault(); setZoom((z) => Math.min(1.4, +(z + 0.1).toFixed(2))) } + else if (key === '-') { e.preventDefault(); setZoom((z) => Math.max(0.7, +(z - 0.1).toFixed(2))) } + else if (/^[0-6]$/.test(key) && !inTextField) { + e.preventDefault() + const level = Number(key) + withEditor((ed) => (level === 0 ? editorCommands.paragraph(ed) : editorCommands.heading(ed, level))) + } + } + document.addEventListener('keydown', onKey) + return () => document.removeEventListener('keydown', onKey) + }, [tab, newDoc, openFile, saveTab, closeTab, withEditor]) + + const pasteFromClipboard = useCallback(async () => { + if (sourceMode) { + // 源码模式下 CodeMirror 自带粘贴处理,聚焦后由浏览器原生粘贴完成 + sourceApiRef.current?.focus() + document.execCommand('paste') + return + } + try { + const text = await navigator.clipboard.readText() + if (text) { withEditor((e) => insertPlainText(e, text)); return } + } catch { /* 权限拒绝时退回 execCommand */ } + document.execCommand('paste') + }, [sourceMode, withEditor]) + + const stateRef = useRef(state) + stateRef.current = state + + /** 粘贴/拖入图片的落盘:桌面模式写入文档 .assets 并回相对路径;未命名文档或 Web 模式退为 data URL。 */ + const handleImageFile = useCallback(async (file: File): Promise => { + const current = activeTab(stateRef.current) + if (isTauri() && current?.path) { + const ext = (file.type.split('/')[1] || 'png').replace('jpeg', 'jpg') + const named = file.name && file.name !== 'image.png' ? file.name : `image-${Date.now()}.${ext}` + const bytes = Array.from(new Uint8Array(await file.arrayBuffer())) + return saveBytesToAssets(current.path, named, bytes) + } + return new Promise((resolve) => { + const reader = new FileReader() + reader.onload = () => resolve(String(reader.result)) + reader.onerror = () => resolve(URL.createObjectURL(file)) + reader.readAsDataURL(file) + }) + }, []) + + const insertImage = useCallback(async () => { + if (!tab) return + if (tauriMode) { + if (!tab.path) { setError('请先保存文档,再插入本地图片(图片会复制到文档同名 .assets 目录并以相对路径引用)。'); return } + const picked = await pickImageFile() + if (!picked) return + try { + const rel = await copyToAssets(picked, tab.path) + withEditor((e) => editorCommands.image(e, rel, baseName(picked))) + } catch (e) { setError(String(e)) } + } else { + const picked = await pickAndReadWebImage() + if (picked) withEditor((e) => editorCommands.image(e, picked.dataUrl, picked.name)) + } + }, [tab, tauriMode, withEditor]) + + const insertAttachment = useCallback(async () => { + if (!tab?.path) { setError('请先保存文档,再插入附件(附件会复制到文档同名 .assets 目录并以链接引用)。'); return } + const picked = await pickAnyFile() + if (!picked) return + try { + const rel = await copyToAssets(picked, tab.path) + withEditor((e) => insertLinkText(e, baseName(picked), rel)) + } catch (e) { setError(String(e)) } + }, [tab, withEditor]) + + const outline = useMemo(() => (tab ? extractOutline(tab.content) : []), [tab]) + + const menus: MenuDef[] = useMemo(() => [ + { + label: '文件', + items: [ + { label: '新建', shortcut: 'Ctrl+N', onClick: newDoc }, + { label: '打开文件…', shortcut: 'Ctrl+O', onClick: () => void openFile() }, + { label: '打开文件夹…', disabled: !tauriMode, onClick: () => void openFolder() }, + { divider: true }, + ...recent.slice(0, 8).map((p) => ({ label: baseName(p), onClick: () => void openPath(p) })), + ...(recent.length ? [{ divider: true } as const] : []), + { label: '保存', shortcut: 'Ctrl+S', disabled: !tab, onClick: () => tab && void saveTab(tab, false) }, + { label: '另存为…', shortcut: 'Ctrl+Shift+S', disabled: !tab, onClick: () => tab && void saveTab(tab, true) }, + { label: '关闭标签页', shortcut: 'Ctrl+W', disabled: !tab, onClick: () => tab && closeTab(tab.id) }, + ], + }, + { + label: '编辑', + items: [ + { label: '撤销', shortcut: 'Ctrl+Z', disabled: sourceMode, onClick: () => withEditor(callUndo) }, + { label: '重做', shortcut: 'Ctrl+Y', disabled: sourceMode, onClick: () => withEditor(callRedo) }, + { divider: true }, + { label: '剪切', onClick: () => document.execCommand('cut') }, + { label: '复制', onClick: () => document.execCommand('copy') }, + { label: '粘贴', onClick: () => { void pasteFromClipboard() } }, + { label: '全选', onClick: () => document.execCommand('selectAll') }, + ], + }, + { + label: '段落', + items: [ + { label: '段落', shortcut: 'Ctrl+0', disabled: sourceMode, onClick: () => withEditor(editorCommands.paragraph) }, + ...[1, 2, 3, 4, 5, 6].map((lv) => ({ + label: `${'一二三四五六'[lv - 1]}级标题`, shortcut: `Ctrl+${lv}`, disabled: sourceMode, + onClick: () => withEditor((e) => editorCommands.heading(e, lv)), + })), + { divider: true }, + { label: '引用', shortcut: 'Ctrl+Shift+Q', disabled: sourceMode, onClick: () => withEditor(editorCommands.blockquote) }, + { label: '无序列表', disabled: sourceMode, onClick: () => withEditor(editorCommands.bulletList) }, + { label: '有序列表', disabled: sourceMode, onClick: () => withEditor(editorCommands.orderedList) }, + { label: '代码块', shortcut: 'Ctrl+Shift+K', disabled: sourceMode, onClick: () => withEditor(editorCommands.codeBlock) }, + { label: '表格(3×3)', shortcut: 'Ctrl+T', disabled: sourceMode, onClick: () => withEditor((e) => editorCommands.insertTable(e)) }, + { label: '数学公式块', disabled: sourceMode, onClick: () => withEditor(insertMathBlock) }, + { label: 'Mermaid 图表', disabled: sourceMode, onClick: () => withEditor(insertMermaidBlock) }, + { label: '水平分割线', disabled: sourceMode, onClick: () => withEditor(editorCommands.hr) }, + ], + }, + { + label: '格式', + items: [ + { label: '加粗', shortcut: 'Ctrl+B', disabled: sourceMode, onClick: () => withEditor(editorCommands.bold) }, + { label: '斜体', shortcut: 'Ctrl+I', disabled: sourceMode, onClick: () => withEditor(editorCommands.italic) }, + { label: '删除线', disabled: sourceMode, onClick: () => withEditor(editorCommands.strikethrough) }, + { label: '行内代码', disabled: sourceMode, onClick: () => withEditor(editorCommands.inlineCode) }, + { label: '超链接…', shortcut: 'Ctrl+K', disabled: sourceMode, onClick: () => setModal('link') }, + { label: '图片…', shortcut: 'Ctrl+Shift+I', disabled: sourceMode, onClick: () => { void insertImage() } }, + { label: '附件…', disabled: sourceMode || !tauriMode, onClick: () => { void insertAttachment() } }, + ], + }, + { + label: '视图', + items: [ + { label: '显示侧边栏', shortcut: 'Ctrl+Shift+L', checked: ui.sidebar, onClick: () => setUi((u) => ({ ...u, sidebar: !u.sidebar })) }, + { label: '文件列表', checked: sidebarMode === 'files', onClick: () => { setSidebarMode('files'); setUi((u) => ({ ...u, sidebar: true })) } }, + { label: '文档大纲', checked: sidebarMode === 'outline', onClick: () => { setSidebarMode('outline'); setUi((u) => ({ ...u, sidebar: true })) } }, + { divider: true }, + { label: '源代码模式', checked: sourceMode, disabled: !tab, onClick: toggleSourceMode }, + { label: '深色主题', checked: ui.theme === 'dark', onClick: () => setUi((u) => ({ ...u, theme: u.theme === 'dark' ? 'light' : 'dark' })) }, + { divider: true }, + { label: '放大', shortcut: 'Ctrl+=', onClick: () => setZoom((z) => Math.min(1.4, +(z + 0.1).toFixed(2))) }, + { label: '缩小', shortcut: 'Ctrl+-', onClick: () => setZoom((z) => Math.max(0.7, +(z - 0.1).toFixed(2))) }, + { label: '恢复默认缩放', onClick: () => setZoom(1) }, + ], + }, + { + label: '帮助', + items: [ + { label: '快捷键说明', onClick: () => setModal('shortcuts') }, + { label: '关于 new-markdown', onClick: () => setModal('about') }, + ], + }, + ], [tab, recent, sourceMode, ui, sidebarMode, tauriMode, newDoc, openFile, openFolder, openPath, saveTab, closeTab, withEditor, toggleSourceMode, insertImage, insertAttachment, pasteFromClipboard]) + + const pendingTitles = pendingClose + ? state.tabs.filter((t) => pendingClose.ids.includes(t.id) && isDirty(t)).map((t) => t.title).join('、') + : '' + + return ( +
+ + + { dispatch({ type: 'activate', id }); setSourceMode(false) }} + onClose={closeTab} + onCloseOthers={(id) => requestClose(state.tabs.filter((t) => t.id !== id).map((t) => t.id), () => dispatch({ type: 'closeOthers', id }))} + onCloseRight={(id) => { + const idx = state.tabs.findIndex((t) => t.id === id) + requestClose(state.tabs.slice(idx + 1).map((t) => t.id), () => dispatch({ type: 'closeRight', id })) + }} + onNew={newDoc} + onMove={(id, toIndex) => dispatch({ type: 'move', id, toIndex })} + /> +
+ {ui.sidebar && ( +
+ void openPath(path)} + onOpenFolder={() => void openFolder()} + outline={outline} + onJumpHeading={jumpHeading} + tauriMode={tauriMode} + /> +
+ )} +
+ {!tab ? ( +
+

没有打开的文档

+

用 Ctrl+N 新建,或 Ctrl+O 打开一个 Markdown 文件。

+
+ + +
+
+ ) : sourceMode ? ( + 正在加载源码编辑器…
}> + dispatch({ type: 'updateContent', id: tab.id, content: text })} + onReady={(api) => { sourceApiRef.current = api }} + /> + + ) : ( + dispatch({ type: 'updateContent', id, content: md })} + onCursor={setCursor} + onImageFile={handleImageFile} + onReady={(api) => { + editorRef.current = api.editor + jumpRef.current = api.jumpToHeading + anchorApiRef.current = api.editor ? { getAnchor: api.getAnchor, setCursorByAnchor: api.setCursorByAnchor } : null + if (api.editor && pendingAnchorRef.current) { + api.setCursorByAnchor(pendingAnchorRef.current) + pendingAnchorRef.current = null + } + }} + /> + )} + +
+ + {pendingClose && ( + setPendingClose(null)} + onDiscard={() => { const { after } = pendingClose; setPendingClose(null); after() }} + onSave={async () => { + const targets = state.tabs.filter((t) => pendingClose.ids.includes(t.id) && isDirty(t)) + for (const t of targets) { + const target = t.id === tab?.id && editorRef.current ? { ...t, content: t.content } : t + const ok = await saveTab(target, false) + if (!ok) return + } + const { after } = pendingClose + setPendingClose(null) + after() + }} + /> + )} + {modal === 'about' && setModal(null)} />} + {modal === 'shortcuts' && setModal(null)} />} + {modal === 'link' && ( + setModal(null)} + onSubmit={(href) => { setModal(null); if (href) withEditor((e) => editorCommands.link(e, href)) }} + /> + )} + {error && setError(null)} />} + + ) +} diff --git a/src/components/EditorPane.tsx b/src/components/EditorPane.tsx new file mode 100644 index 0000000..08db6e2 --- /dev/null +++ b/src/components/EditorPane.tsx @@ -0,0 +1,123 @@ +import { useCallback, useEffect, useRef, useState } from 'react' +import TableToolbar from './TableToolbar' +import type { Editor } from '@milkdown/kit/core' +import { editorViewCtx } from '@milkdown/kit/core' +import { TextSelection } from '@milkdown/kit/prose/state' +import { createMarkdownEditor, getMarkdown, type CursorInfo } from '../editor/editor' +import { findBlockIndex, type CursorAnchor } from '../editor/cursorSync' + +export interface EditorPaneApi { + editor: Editor | null + jumpToHeading: (text: string) => void + getAnchor: () => CursorAnchor | null + setCursorByAnchor: (anchor: CursorAnchor) => void +} + +interface Props { + tabId: string + initialMarkdown: string + onMarkdown: (tabId: string, markdown: string) => void + onCursor: (cursor: CursorInfo) => void + onReady: (api: EditorPaneApi) => void + onImageFile?: (file: File) => Promise +} + +const EMPTY_API: EditorPaneApi = { + editor: null, + jumpToHeading: () => undefined, + getAnchor: () => null, + setCursorByAnchor: () => undefined, +} + +/** 单标签编辑器宿主:挂载时以标签内容建模,卸载前回写最终序列化文本,保证切标签不丢内容。 */ +export default function EditorPane({ tabId, initialMarkdown, onMarkdown, onCursor, onReady, onImageFile }: Props) { + const wrapRef = useRef(null) + const editorObjRef = useRef(null) + const [tableBar, setTableBar] = useState<{ top: number; left: number } | null>(null) + + const tableElRef = useRef(null) + const updateTableBar = useCallback(() => { + const wrap = wrapRef.current + const el = tableElRef.current + if (!wrap || !el) { setTableBar(null); return } + const wr = wrap.getBoundingClientRect() + const tr = el.getBoundingClientRect() + setTableBar({ top: Math.max(0, tr.top - wr.top - 38), left: Math.max(0, tr.left - wr.left) }) + }, []) + const hostRef = useRef(null) + const initialRef = useRef(initialMarkdown) + const callbacksRef = useRef({ onMarkdown, onCursor, onReady, onImageFile }) + callbacksRef.current = { onMarkdown, onCursor, onReady, onImageFile } + + useEffect(() => { + if (!hostRef.current) return + const editor = createMarkdownEditor(hostRef.current, initialRef.current, { + onMarkdown: (md) => callbacksRef.current.onMarkdown(tabId, md), + onCursor: (c) => callbacksRef.current.onCursor(c), + onTableContext: (inTable, el) => { tableElRef.current = el; if (inTable) updateTableBar(); else setTableBar(null) }, + }, { onImageFile: (file) => callbacksRef.current.onImageFile ? callbacksRef.current.onImageFile(file) : Promise.resolve(URL.createObjectURL(file)) }) + editorObjRef.current = editor + const jumpToHeading = (text: string) => { + const els = hostRef.current?.querySelectorAll('h1,h2,h3,h4,h5,h6') ?? [] + for (const el of els) { + if (el.textContent?.trim() === text) { + el.scrollIntoView({ block: 'center', behavior: 'smooth' }) + break + } + } + } + const getAnchor = (): CursorAnchor | null => { + try { + return editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + const $from = view.state.selection.$from + return { blockText: $from.parent.textContent, offsetInBlock: $from.parentOffset } + }) + } catch { return null } + } + const setCursorByAnchor = (anchor: CursorAnchor) => { + try { + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + const doc = view.state.doc + const blocks: { text: string; start: number; size: number }[] = [] + doc.descendants((node, pos) => { + if (node.isTextblock) blocks.push({ text: node.textContent, start: pos + 1, size: node.content.size }) + return true + }) + const idx = findBlockIndex(blocks.map((b) => b.text), anchor) + if (idx < 0) return + const target = blocks[idx] + const pos = target.start + Math.max(0, Math.min(anchor.offsetInBlock, target.size)) + view.dispatch(view.state.tr.setSelection(TextSelection.create(doc, pos)).scrollIntoView()) + view.focus() + }) + } catch { /* 定位失败静默:不打断模式切换 */ } + } + editor.create() + .then(() => callbacksRef.current.onReady({ editor, jumpToHeading, getAnchor, setCursorByAnchor })) + .catch((e) => console.error('编辑器创建失败', e)) + const scrollParent = wrapRef.current?.closest('.editor-scroll') + const onScroll = () => { if (editorObjRef.current) updateTableBar() } + scrollParent?.addEventListener('scroll', onScroll, { passive: true }) + return () => { + scrollParent?.removeEventListener('scroll', onScroll) + editorObjRef.current = null + setTableBar(null) + try { + callbacksRef.current.onMarkdown(tabId, getMarkdown(editor)) + } catch { /* 编辑器未就绪时跳过回写 */ } + callbacksRef.current.onReady(EMPTY_API) + editor.destroy().catch(() => undefined) + } + }, [tabId, updateTableBar]) + + return ( +
+ {tableBar && editorObjRef.current && ( + + )} +
+
+ ) +} diff --git a/src/components/MenuBar.tsx b/src/components/MenuBar.tsx new file mode 100644 index 0000000..fa857b7 --- /dev/null +++ b/src/components/MenuBar.tsx @@ -0,0 +1,71 @@ +import { useEffect, useRef, useState } from 'react' + +export interface MenuItemDef { + label?: string + shortcut?: string + checked?: boolean + disabled?: boolean + divider?: boolean + onClick?: () => void +} + +export interface MenuDef { + label: string + items: MenuItemDef[] +} + +/** 自绘菜单栏:菜单数据由 App 注入,全部条目均为真实动作(无占位项)。 + * 支持点击展开、悬停切换、Esc/点击外部关闭。 */ +export default function MenuBar({ menus }: { menus: MenuDef[] }) { + const [open, setOpen] = useState(null) + const ref = useRef(null) + + useEffect(() => { + const onDoc = (e: MouseEvent) => { + if (ref.current && !ref.current.contains(e.target as Node)) setOpen(null) + } + const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') setOpen(null) } + document.addEventListener('mousedown', onDoc) + document.addEventListener('keydown', onKey) + return () => { + document.removeEventListener('mousedown', onDoc) + document.removeEventListener('keydown', onKey) + } + }, []) + + return ( + + ) +} diff --git a/src/components/Modals.tsx b/src/components/Modals.tsx new file mode 100644 index 0000000..41dd1b3 --- /dev/null +++ b/src/components/Modals.tsx @@ -0,0 +1,96 @@ +import { useState } from 'react' + +function Shell({ children, onCancel }: { children: React.ReactNode; onCancel?: () => void }) { + return ( +
+
e.stopPropagation()}>{children}
+
+ ) +} + +export function ConfirmSaveModal({ title, onSave, onDiscard, onCancel }: { + title: string + onSave: () => void + onDiscard: () => void + onCancel: () => void +}) { + return ( + +

保存修改?

+

「{title}」有未保存的修改,关闭前是否保存?

+
+ + + +
+
+ ) +} + +export function AboutModal({ onClose }: { onClose: () => void }) { + return ( + +

new-markdown

+

Windows Markdown 所见即所得编辑器 · 版本 0.1.0(阶段 1)

+

内核:Milkdown 7.23(ProseMirror)· 桌面:Tauri 2

+
+
+ ) +} + +const SHORTCUTS: [string, string][] = [ + ['新建文档', 'Ctrl+N'], ['打开文件', 'Ctrl+O'], ['保存', 'Ctrl+S'], ['另存为', 'Ctrl+Shift+S'], + ['关闭标签页', 'Ctrl+W'], ['撤销 / 重做', 'Ctrl+Z / Ctrl+Y'], + ['加粗 / 斜体', 'Ctrl+B / Ctrl+I'], ['插入链接', 'Ctrl+K'], + ['段落 / 一级标题', 'Ctrl+0 / Ctrl+1'], ['二级 ~ 六级标题', 'Ctrl+2 ~ Ctrl+6'], + ['引用', 'Ctrl+Shift+Q'], ['代码块', 'Ctrl+Shift+K'], + ['显示/隐藏侧边栏', 'Ctrl+Shift+L'], ['放大 / 缩小', 'Ctrl+= / Ctrl+-'], +] + +export function ShortcutsModal({ onClose }: { onClose: () => void }) { + return ( + +

快捷键

+ + + {SHORTCUTS.map(([name, key]) => ( + + ))} + +
{name}{key}
+

需求表里 Ctrl+0 同时挂了「段落」与「恢复默认缩放」,本实现取「段落」(与 Typora 一致),恢复缩放走视图菜单,避免同键双义。阶段 6 设置中心提供快捷键自定义与冲突检测。

+
+
+ ) +} + +export function LinkModal({ onSubmit, onCancel }: { onSubmit: (href: string) => void; onCancel: () => void }) { + const [href, setHref] = useState('https://') + return ( + +

插入链接

+ setHref(e.target.value)} + onKeyDown={(e) => { if (e.key === 'Enter') onSubmit(href.trim()) }} + placeholder="https://example.com" + /> +
+ + +
+
+ ) +} + +export function ErrorModal({ message, onClose }: { message: string; onClose: () => void }) { + return ( + +

操作失败

+

{message}

+
+
+ ) +} diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx new file mode 100644 index 0000000..6e8c309 --- /dev/null +++ b/src/components/Sidebar.tsx @@ -0,0 +1,121 @@ +import { useCallback, useEffect, useState } from 'react' +import { listDir, type DirEntry } from '../services/platform' +import type { OutlineItem } from '../utils/text' +import { baseName } from '../utils/text' + +interface Props { + mode: 'files' | 'outline' + onModeChange: (mode: 'files' | 'outline') => void + workspaceRoot: string | null + activePath: string | null + onOpenFile: (path: string) => void + onOpenFolder: () => void + outline: OutlineItem[] + onJumpHeading: (item: OutlineItem) => void + tauriMode: boolean +} + +export default function Sidebar(p: Props) { + return ( + + ) +} + +function FileTree({ root, activePath, onOpenFile }: { root: string; activePath: string | null; onOpenFile: (path: string) => void }) { + const [refreshKey, setRefreshKey] = useState(0) + return ( +
+
+ {baseName(root)} + +
+ +
+ ) +} + +function TreeLevel({ dir, depth, activePath, onOpenFile, refreshKey }: { + dir: string + depth: number + activePath: string | null + onOpenFile: (path: string) => void + refreshKey: number +}) { + const [entries, setEntries] = useState(null) + const [error, setError] = useState(null) + const [expanded, setExpanded] = useState>(new Set()) + + const load = useCallback(async () => { + try { + setEntries(await listDir(dir)) + setError(null) + } catch (e) { + setError(String(e)) + } + }, [dir]) + + useEffect(() => { void load() }, [load, refreshKey]) + + if (error) return
{error}
+ if (!entries) return
加载中…
+ + const toggle = (path: string) => { + setExpanded((prev) => { + const next = new Set(prev) + if (next.has(path)) next.delete(path) + else next.add(path) + return next + }) + } + + return ( +
+ {entries.map((entry) => ( +
+ + {entry.isDir && expanded.has(entry.path) && ( + + )} +
+ ))} +
+ ) +} diff --git a/src/components/SourceEditor.tsx b/src/components/SourceEditor.tsx new file mode 100644 index 0000000..8281d38 --- /dev/null +++ b/src/components/SourceEditor.tsx @@ -0,0 +1,88 @@ +import { useEffect, useRef } from 'react' +import { EditorState } from '@codemirror/state' +import { EditorView, keymap, lineNumbers, highlightActiveLine, drawSelection } from '@codemirror/view' +import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands' +import { markdown } from '@codemirror/lang-markdown' +import { languages } from '@codemirror/language-data' +import { syntaxHighlighting, defaultHighlightStyle, indentOnInput, bracketMatching } from '@codemirror/language' +import { oneDark } from '@codemirror/theme-one-dark' +import { anchorFromMarkdown, type CursorAnchor } from '../editor/cursorSync' + +export interface SourceEditorApi { + jumpToLine: (line: number) => void + getAnchor: () => CursorAnchor | null + focus: () => void +} + +interface Props { + tabId: string + initialText: string + initialCursorOffset: number + dark: boolean + onChange: (text: string) => void + onReady: (api: SourceEditorApi) => void +} + +/** 源码模式编辑器(CodeMirror 6):行号、Markdown 高亮、历史栈与渲染模式相互独立,进入/退出靠锚点同步光标。 */ +export default function SourceEditor({ tabId, initialText, initialCursorOffset, dark, onChange, onReady }: Props) { + const hostRef = useRef(null) + const viewRef = useRef(null) + const initialRef = useRef({ initialText, initialCursorOffset }) + const callbacksRef = useRef({ onChange, onReady }) + callbacksRef.current = { onChange, onReady } + + useEffect(() => { + if (!hostRef.current) return + const { initialText: doc, initialCursorOffset: cursor } = initialRef.current + const view = new EditorView({ + parent: hostRef.current, + state: EditorState.create({ + doc, + selection: { anchor: Math.max(0, Math.min(cursor, doc.length)) }, + extensions: [ + lineNumbers(), + highlightActiveLine(), + drawSelection(), + history(), + indentOnInput(), + bracketMatching(), + syntaxHighlighting(defaultHighlightStyle, { fallback: true }), + keymap.of([...defaultKeymap, ...historyKeymap, indentWithTab]), + markdown({ codeLanguages: languages }), + EditorView.lineWrapping, + EditorView.updateListener.of((update) => { + if (update.docChanged) callbacksRef.current.onChange(update.state.doc.toString()) + }), + EditorView.theme({ + '&': { height: '100%', fontSize: '14px', backgroundColor: 'transparent' }, + '.cm-content': { fontFamily: '"Cascadia Code", Consolas, monospace', padding: '24px 0', lineHeight: '1.7' }, + '.cm-gutters': { backgroundColor: 'transparent', border: 'none' }, + }), + ...(dark ? [oneDark] : []), + ], + }), + }) + viewRef.current = view + view.focus() + callbacksRef.current.onReady({ + jumpToLine: (line) => { + const target = Math.max(1, Math.min(line + 1, view.state.doc.lines)) + const pos = view.state.doc.line(target).from + view.dispatch({ selection: { anchor: pos }, effects: EditorView.scrollIntoView(pos, { y: 'center' }) }) + view.focus() + }, + getAnchor: () => anchorFromMarkdown(view.state.doc.toString(), view.state.selection.main.head), + focus: () => view.focus(), + }) + return () => { + // 卸载前回写最终文本,避免切换瞬间丢失最后一次输入 + callbacksRef.current.onChange(view.state.doc.toString()) + view.destroy() + viewRef.current = null + } + // dark 变化时整组件由父级 key 重挂载处理,这里只随 tabId 建/销 + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [tabId]) + + return
+} diff --git a/src/components/StatusBar.tsx b/src/components/StatusBar.tsx new file mode 100644 index 0000000..d29398a --- /dev/null +++ b/src/components/StatusBar.tsx @@ -0,0 +1,33 @@ +import type { CursorInfo } from '../editor/editor' + +interface Props { + words: number + chars: number + lines: number + cursor: CursorInfo + encoding: string + lineEnding: string + dirty: boolean + sourceMode: boolean + tauriMode: boolean + zoom: number +} + +export default function StatusBar(p: Props) { + return ( +
+ 字数:{p.words} + 字符:{p.chars} + 行:{p.cursor.line},列:{p.cursor.col} + 共 {p.lines} 行 + {p.encoding} + {p.lineEnding} + {p.dirty ? '未保存' : '已保存'} + {p.sourceMode ? '源代码模式' : '即时渲染'} + + {Math.round(p.zoom * 100)}% + {p.tauriMode ? '桌面模式' : 'Web 降级模式(调试)'} + +
+ ) +} diff --git a/src/components/TabBar.tsx b/src/components/TabBar.tsx new file mode 100644 index 0000000..b801bf4 --- /dev/null +++ b/src/components/TabBar.tsx @@ -0,0 +1,64 @@ +import { useState } from 'react' +import type { DocTab } from '../stores/tabs' +import { isDirty } from '../stores/tabs' + +interface Props { + tabs: DocTab[] + activeId: string | null + onActivate: (id: string) => void + onClose: (id: string) => void + onCloseOthers: (id: string) => void + onCloseRight: (id: string) => void + onNew: () => void + onMove: (id: string, toIndex: number) => void +} + +export default function TabBar({ tabs, activeId, onActivate, onClose, onCloseOthers, onCloseRight, onNew, onMove }: Props) { + const [menuFor, setMenuFor] = useState<{ id: string; x: number; y: number } | null>(null) + const [dragId, setDragId] = useState(null) + + if (tabs.length === 0) return null + + return ( +
setMenuFor(null)}> + {tabs.map((tab, index) => ( +
setDragId(tab.id)} + onDragOver={(e) => { + e.preventDefault() + if (dragId && dragId !== tab.id) { + onMove(dragId, index) + } + }} + onDragEnd={() => setDragId(null)} + onClick={() => onActivate(tab.id)} + onContextMenu={(e) => { + e.preventDefault() + e.stopPropagation() + setMenuFor({ id: tab.id, x: e.clientX, y: e.clientY }) + }} + title={tab.path ?? tab.title} + > + {tab.title} + {isDirty(tab) && ●} + +
+ ))} + + {menuFor && ( +
+ + + +
+ )} +
+ ) +} diff --git a/src/components/TableToolbar.tsx b/src/components/TableToolbar.tsx new file mode 100644 index 0000000..6a0c650 --- /dev/null +++ b/src/components/TableToolbar.tsx @@ -0,0 +1,29 @@ +import type { Editor } from '@milkdown/kit/core' +import { editorCommands } from '../editor/commands' + +interface Props { + editor: Editor + top: number + left: number +} + +/** 表格浮动工具栏:光标在表格内时出现在表格上方(EditorPane 负责定位与显隐)。 */ +export default function TableToolbar({ editor, top, left }: Props) { + const btn = (label: string, fn: () => void, title?: string) => ( + + ) + return ( +
+ {btn('+行', () => editorCommands.addRowAfter(editor), '在下方新增行')} + {btn('+列', () => editorCommands.addColAfter(editor), '在右侧新增列')} + {btn('删行', () => editorCommands.deleteRow(editor), '删除当前行')} + {btn('删列', () => editorCommands.deleteCol(editor), '删除当前列')} + + {btn('左齐', () => editorCommands.setAlign(editor, 'left'), '列左对齐')} + {btn('居中', () => editorCommands.setAlign(editor, 'center'), '列居中')} + {btn('右齐', () => editorCommands.setAlign(editor, 'right'), '列右对齐')} + + {btn('删表', () => editorCommands.deleteTable(editor), '删除整个表格')} +
+ ) +} diff --git a/src/components/TitleBar.tsx b/src/components/TitleBar.tsx new file mode 100644 index 0000000..01db0ff --- /dev/null +++ b/src/components/TitleBar.tsx @@ -0,0 +1,42 @@ +import { isTauri } from '../services/platform' + +interface Props { + docTitle: string + dirty: boolean +} + +/** 自定义标题栏(Tauri decorations=false):拖动区 + 文档名 + 窗口控制。 + * Web 降级模式下不渲染窗口控制(浏览器自有边框),避免假按钮。 */ +export default function TitleBar({ docTitle, dirty }: Props) { + const tauri = isTauri() + + const winAction = async (action: 'min' | 'max' | 'close') => { + const { getCurrentWindow } = await import('@tauri-apps/api/window') + const win = getCurrentWindow() + if (action === 'min') await win.minimize() + else if (action === 'close') await win.close() + else { + const maximized = await win.isMaximized() + if (maximized) await win.unmaximize() + else await win.maximize() + } + } + + return ( +
+ M + + {docTitle} + {dirty && ●} + — new-markdown + + {tauri && ( + + + + + + )} +
+ ) +} diff --git a/src/editor/commands.ts b/src/editor/commands.ts new file mode 100644 index 0000000..9643d2a --- /dev/null +++ b/src/editor/commands.ts @@ -0,0 +1,134 @@ +// 段落/格式命令:全部走 Milkdown 命令系统(一命令 = 一事务 = 一步撤销)。 +import type { Editor } from '@milkdown/kit/core' +import { commandsCtx } from '@milkdown/kit/core' +import { + toggleStrongCommand, toggleEmphasisCommand, toggleInlineCodeCommand, toggleLinkCommand, + wrapInHeadingCommand, turnIntoTextCommand, wrapInBlockquoteCommand, + wrapInBulletListCommand, wrapInOrderedListCommand, createCodeBlockCommand, insertHrCommand, + insertImageCommand, +} from '@milkdown/kit/preset/commonmark' +import { + toggleStrikethroughCommand, insertTableCommand, addRowAfterCommand, addColAfterCommand, + setAlignCommand, goToNextTableCellCommand, goToPrevTableCellCommand, +} from '@milkdown/kit/preset/gfm' +import { editorViewCtx } from '@milkdown/kit/core' +import { TextSelection } from '@milkdown/kit/prose/state' +import { deleteRow, deleteColumn, deleteTable } from '@milkdown/kit/prose/tables' + +function call(editor: Editor, key: unknown, payload?: unknown) { + editor.action((ctx) => { + // commandsCtx.call 的键是带载荷类型的 CmdKey;此处统一擦除为 unknown 做分发, + // 各命令的载荷在下方调用点按对应命令的签名传入。 + const manager = ctx.get(commandsCtx) as unknown as { call: (k: unknown, p?: unknown) => boolean } + manager.call(key, payload) + }) +} + +export const editorCommands = { + bold: (e: Editor) => call(e, toggleStrongCommand.key), + italic: (e: Editor) => call(e, toggleEmphasisCommand.key), + strikethrough: (e: Editor) => call(e, toggleStrikethroughCommand.key), + inlineCode: (e: Editor) => call(e, toggleInlineCodeCommand.key), + link: (e: Editor, href: string) => call(e, toggleLinkCommand.key, { href }), + paragraph: (e: Editor) => call(e, turnIntoTextCommand.key), + heading: (e: Editor, level: number) => call(e, wrapInHeadingCommand.key, level), + blockquote: (e: Editor) => call(e, wrapInBlockquoteCommand.key), + bulletList: (e: Editor) => call(e, wrapInBulletListCommand.key), + orderedList: (e: Editor) => call(e, wrapInOrderedListCommand.key), + codeBlock: (e: Editor) => call(e, createCodeBlockCommand.key), + hr: (e: Editor) => call(e, insertHrCommand.key), + image: (e: Editor, src: string, alt: string) => call(e, insertImageCommand.key, { src, alt }), + // ——— 表格(阶段 3)——— + insertTable: (e: Editor, row = 3, col = 3) => call(e, insertTableCommand.key, { row, col }), + addRowAfter: (e: Editor) => call(e, addRowAfterCommand.key), + addColAfter: (e: Editor) => call(e, addColAfterCommand.key), + setAlign: (e: Editor, align: 'left' | 'center' | 'right') => setAlignColumn(e, align), + nextCell: (e: Editor) => call(e, goToNextTableCellCommand.key), + prevCell: (e: Editor) => call(e, goToPrevTableCellCommand.key), + deleteRow: (e: Editor) => proseTableCommand(e, deleteRow), + deleteCol: (e: Editor) => proseTableCommand(e, deleteColumn), + deleteTable: (e: Editor) => proseTableCommand(e, deleteTable), +} + +/** + * 整列对齐:GFM 的对齐由表头行定义(序列化时从表头单元格 attrs 汇总), + * setAlignCommand 本身只改选区所在单元格;这里先把选区移到同列表头格执行,再恢复原选区, + * 这样用户在任意数据格点对齐都生效。 + */ +export function setAlignColumn(editor: Editor, align: 'left' | 'center' | 'right') { + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + const { state } = view + const $from = state.selection.$from + let cellPos = -1 + let rowPos = -1 + let tablePos = -1 + for (let d = 1; d <= $from.depth; d++) { + const name = $from.node(d)?.type.name + if (name === 'table_cell' || name === 'table_header') cellPos = $from.before(d) + if (name === 'table_row' || name === 'table_header_row') rowPos = $from.before(d) + if (name === 'table') tablePos = $from.before(d) + } + if (cellPos < 0 || rowPos < 0 || tablePos < 0) return + const rowNode = state.doc.nodeAt(rowPos) + const tableNode = state.doc.nodeAt(tablePos) + if (!rowNode || !tableNode) return + // 当前列下标:行内排在当前格之前的单元格数量 + let colIndex = 0 + let acc = rowPos + 1 + rowNode.forEach((child) => { + if (acc < cellPos) colIndex += 1 + acc += child.nodeSize + }) + // 表头行同列单元格的文档位置 + const headerRow = tableNode.firstChild + if (!headerRow) return + let headerCellPos = -1 + let hacc = tablePos + 1 + 1 // 表格内容起点 + 表头行边框 + headerRow.forEach((child, _offset, index) => { + if (index === colIndex) headerCellPos = hacc + hacc += child.nodeSize + }) + if (headerCellPos < 0) return + const original = state.selection + view.dispatch(state.tr.setSelection(TextSelection.create(state.doc, headerCellPos + 2))) + ctx.get(commandsCtx).call(setAlignCommand.key, align) + const now = view.state + view.dispatch(now.tr.setSelection(TextSelection.create(now.doc, Math.min(original.from, now.doc.content.size)))) + }) +} + +/** 插入 Mermaid 代码块(language=mermaid,节点视图自动渲染预览)。 */ +export function insertMermaidBlock(editor: Editor) { + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + const schema = view.state.schema + const type = schema.nodes.code_block + if (!type) return + const node = type.create({ language: 'mermaid' }, schema.text('graph TD\n A[开始] --> B[结束]')) + view.dispatch(view.state.tr.replaceSelectionWith(node).scrollIntoView()) + view.focus() + }) +} + +/** 插入数学公式块(plugin-math 的 math_block 节点,序列化为 $$ 块)。 */ +export function insertMathBlock(editor: Editor) { + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + const schema = view.state.schema + const type = schema.nodes.math_block + if (!type) return + // math_block 是 atom 节点,LaTeX 存在 attrs.value 中(plugin-math 的 schema 定义),不走文本内容 + const node = type.create({ value: 'E = mc^2' }) + view.dispatch(view.state.tr.replaceSelectionWith(node).scrollIntoView()) + view.focus() + }) +} + +type ProseTableCmd = (state: unknown, dispatch: (tr: unknown) => void) => boolean +function proseTableCommand(editor: Editor, cmd: unknown) { + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + ;(cmd as ProseTableCmd)(view.state, view.dispatch as (tr: unknown) => void) + }) +} diff --git a/src/editor/cursorSync.ts b/src/editor/cursorSync.ts new file mode 100644 index 0000000..85f9321 --- /dev/null +++ b/src/editor/cursorSync.ts @@ -0,0 +1,49 @@ +// 渲染模式 ⇄ 源码模式的光标同步:以「当前文本块的纯文本 + 块内偏移」为锚点互相定位。 +// 这是近似同步(需求 §4.3 的口径即「尽可能一致」):锚点文本在对方文档中唯一出现时精确命中, +// 重复出现时取第一个匹配;找不到时回落到文档开头,绝不抛错、不丢内容。 + +export interface CursorAnchor { + blockText: string + offsetInBlock: number +} + +const LEADING_MARKERS = /^\s*(?:#{1,6}\s+|>\s?|[-*+]\s+(?:\[[ xX]\]\s+)?|\d+[.)]\s+)/ + +/** 源码中某个偏移所在行的纯文本与行内偏移(剥掉行首 Markdown 标记)。 */ +export function anchorFromMarkdown(markdown: string, offset: number): CursorAnchor { + const clamped = Math.max(0, Math.min(offset, markdown.length)) + const lineStart = markdown.lastIndexOf('\n', Math.max(0, clamped - 1)) + 1 + let lineEnd = markdown.indexOf('\n', clamped) + if (lineEnd < 0) lineEnd = markdown.length + const line = markdown.slice(lineStart, lineEnd) + const marker = LEADING_MARKERS.exec(line)?.[0] ?? '' + const plain = line.slice(marker.length) + const offsetInBlock = Math.max(0, Math.min(clamped - lineStart - marker.length, plain.length)) + return { blockText: plain, offsetInBlock } +} + +/** 在源码中定位锚点块,返回应放置的光标偏移;找不到返回 0。 */ +export function offsetInMarkdown(markdown: string, anchor: CursorAnchor): number { + if (!anchor.blockText) return 0 + const lines = markdown.split('\n') + let pos = 0 + for (const line of lines) { + const marker = LEADING_MARKERS.exec(line)?.[0] ?? '' + const plain = line.slice(marker.length) + if (plain === anchor.blockText) { + return pos + marker.length + Math.min(anchor.offsetInBlock, plain.length) + } + pos += line.length + 1 + } + // 退一步:子串查找(锚点块与源码行不完全一致时,如行内格式被序列化改写) + const idx = markdown.indexOf(anchor.blockText) + return idx >= 0 ? idx + Math.min(anchor.offsetInBlock, anchor.blockText.length) : 0 +} + +/** 在渲染文档的文本块序列中定位锚点块下标;找不到返回 -1。 */ +export function findBlockIndex(blockTexts: string[], anchor: CursorAnchor): number { + if (!anchor.blockText) return -1 + const exact = blockTexts.findIndex((t) => t === anchor.blockText) + if (exact >= 0) return exact + return blockTexts.findIndex((t) => t.includes(anchor.blockText) || anchor.blockText.includes(t)) +} diff --git a/src/editor/editor.ts b/src/editor/editor.ts new file mode 100644 index 0000000..6038026 --- /dev/null +++ b/src/editor/editor.ts @@ -0,0 +1,137 @@ +// 编辑器装配层(阶段 0 工厂的产品化版本):UI 与测试共用此创建路径。 +// 阶段 2/3 的插件(标记显隐装饰、数学、Mermaid、高亮)在此按序叠加,不改调用方。 +import { + Editor, rootCtx, defaultValueCtx, editorViewCtx, serializerCtx, commandsCtx, + remarkStringifyOptionsCtx, +} from '@milkdown/kit/core' +import { commonmark } from '@milkdown/kit/preset/commonmark' +import { gfm } from '@milkdown/kit/preset/gfm' +import { history, undoCommand, redoCommand } from '@milkdown/kit/plugin/history' +import { listener, listenerCtx } from '@milkdown/kit/plugin/listener' +import { clipboard } from '@milkdown/kit/plugin/clipboard' +import { indent } from '@milkdown/kit/plugin/indent' +import { math } from '@milkdown/plugin-math' +import { upload, uploadConfig, type UploadOptions } from '@milkdown/kit/plugin/upload' +import { createSyntaxRevealPlugin, createCodeBlockTabPlugin, createTableTabPlugin, selectionInTable } from './plugins' +import { createListItemViewPlugin, createCodeBlockViewPlugin } from './nodeViews' + +export interface CursorInfo { line: number; col: number } + +export interface EditorCallbacks { + onMarkdown?: (markdown: string) => void + onCursor?: (cursor: CursorInfo) => void + /** 选区进出表格时通知(阶段 3 表格工具栏);第二参为当前表格 DOM(不在表格内时为 null) */ + onTableContext?: (inTable: boolean, tableEl: HTMLElement | null) => void +} + +export interface EditorOptions { + /** 粘贴/拖入图片文件的落盘处理:返回应写入文档的图片地址(相对路径或 data URL)。缺省用会话级对象 URL。 */ + onImageFile?: (file: File) => Promise +} + +export function createMarkdownEditor(root: HTMLElement, initialMarkdown: string, callbacks: EditorCallbacks = {}, options: EditorOptions = {}) { + const editor = Editor.make() + .config((ctx) => { + ctx.set(rootCtx, root) + ctx.set(defaultValueCtx, initialMarkdown) + // 序列化风格对齐 Typora 习惯(阶段 0 定稿):无序列表用 `-` + ctx.set(remarkStringifyOptionsCtx, { bullet: '-' }) + const lm = ctx.get(listenerCtx) + if (callbacks.onMarkdown) { + lm.markdownUpdated((_ctx, markdown) => callbacks.onMarkdown?.(markdown)) + } + if (callbacks.onCursor || callbacks.onTableContext) { + lm.selectionUpdated((selCtx, selection) => { + callbacks.onCursor?.(cursorFromSelection(selection)) + if (callbacks.onTableContext) { + const inTable = selectionInTable(selection as never) + let tableEl: HTMLElement | null = null + if (inTable) { + try { + const view = selCtx.get(editorViewCtx) + const at = view.domAtPos(selection.from) + const base = at.node.nodeType === Node.ELEMENT_NODE ? (at.node as Element) : at.node.parentElement + tableEl = (base?.closest('table') as HTMLElement | null) ?? null + } catch { /* 定位失败时工具栏不显示 */ } + } + callbacks.onTableContext(inTable, tableEl) + } + }) + } + ctx.update(uploadConfig.key, (prev: UploadOptions) => ({ + ...prev, + uploader: (async (files: FileList, schema: { nodes: { image?: { createAndFill: (attrs: { src: string; alt: string }) => unknown } } }) => { + const nodes: unknown[] = [] + for (const file of Array.from(files)) { + if (!file.type.startsWith('image/')) continue + const src = options.onImageFile ? await options.onImageFile(file) : URL.createObjectURL(file) + const imageNode = schema.nodes.image?.createAndFill({ src, alt: file.name }) + if (imageNode) nodes.push(imageNode) + } + return nodes + }) as UploadOptions['uploader'], + })) + }) + .use(commonmark) + .use(gfm) + .use(history) + .use(listener) + .use(clipboard) + .use(indent) + .use(createSyntaxRevealPlugin()) + .use(createCodeBlockTabPlugin()) + .use(createTableTabPlugin()) + .use(createListItemViewPlugin()) + .use(createCodeBlockViewPlugin()) + .use(math) + .use(upload) + return editor +} + +interface PmSelection { + $from: { + parentOffset: number + depth: number + before: (depth?: number) => number + doc: { + descendants: (fn: (node: { isTextblock: boolean }, pos: number) => boolean | void) => void + } + } +} + +/** 由 ProseMirror 选区推导行列:行 = 选区所在文本块在全文文本块序列中的序号;列 = 块内偏移 + 1。 */ +export function cursorFromSelection(selection: unknown): CursorInfo { + const sel = selection as PmSelection + const $from = sel.$from + const parentPos = $from.before($from.depth) + let line = 0 + let current = 1 + $from.doc.descendants((node, pos) => { + if (node.isTextblock) { + line += 1 + if (pos === parentPos) current = line + } + return true + }) + return { line: current, col: $from.parentOffset + 1 } +} + +export function getMarkdown(editor: Editor): string { + return editor.action((ctx) => { + const serializer = ctx.get(serializerCtx) + const view = ctx.get(editorViewCtx) + return serializer(view.state.doc) + }) +} + +export function callUndo(editor: Editor) { + editor.action((ctx) => ctx.get(commandsCtx).call(undoCommand.key)) +} + +export function callRedo(editor: Editor) { + editor.action((ctx) => ctx.get(commandsCtx).call(redoCommand.key)) +} + +export function focusEditor(editor: Editor) { + editor.action((ctx) => ctx.get(editorViewCtx).focus()) +} diff --git a/src/editor/nodeViews.ts b/src/editor/nodeViews.ts new file mode 100644 index 0000000..3650b61 --- /dev/null +++ b/src/editor/nodeViews.ts @@ -0,0 +1,204 @@ +// 任务列表节点视图(阶段 2 补齐): +// Kit 的 preset-gfm 只把任务项渲染为
  • ,没有可点击的复选框(那是 Crepe 的组件层能力)。 +// 这里给 list_item 注册自有 NodeView:任务项在内容前渲染真实 checkbox,点击切换 checked 属性 +//(走一条事务,可撤销;序列化自动变回 - [ ] / - [x])。普通列表项不渲染复选框,外观不变。 +import { nodeViewCtx } from '@milkdown/kit/core' +import type { MilkdownPlugin } from '@milkdown/kit/ctx' +import type { NodeViewConstructor } from '@milkdown/kit/prose/view' + +interface ListItemNode { + type: { name: string } + attrs: { checked?: boolean | null; label?: string; listType?: string; spread?: boolean } +} + +const listItemView: NodeViewConstructor = (node, view, getPos) => { + const item = node as unknown as ListItemNode + const dom = document.createElement('li') + dom.dataset.itemType = item.attrs.checked != null ? 'task' : 'list' + if (item.attrs.label) dom.dataset.label = item.attrs.label + if (item.attrs.listType) dom.dataset.listType = item.attrs.listType + if (item.attrs.checked != null) dom.dataset.checked = String(item.attrs.checked) + + let checkbox: HTMLInputElement | null = null + if (item.attrs.checked != null) { + dom.classList.add('task-item') + checkbox = document.createElement('input') + checkbox.type = 'checkbox' + checkbox.className = 'task-checkbox' + checkbox.checked = Boolean(item.attrs.checked) + checkbox.contentEditable = 'false' + checkbox.addEventListener('mousedown', (e) => e.preventDefault()) + checkbox.addEventListener('click', (e) => { + e.preventDefault() + const pos = getPos() + if (pos == null) return + const current = view.state.doc.nodeAt(pos) + if (!current) return + const next = !current.attrs.checked + view.dispatch(view.state.tr.setNodeMarkup(pos, undefined, { ...current.attrs, checked: next })) + }) + dom.appendChild(checkbox) + } + + const contentDOM = document.createElement('div') + contentDOM.className = 'task-content' + contentDOM.style.display = 'contents' + dom.appendChild(contentDOM) + + return { + dom, + contentDOM, + update: (updated) => { + const next = updated as unknown as ListItemNode + if (next.type.name !== 'list_item') return false + const wasTask = item.attrs.checked != null + const isTask = next.attrs.checked != null + if (wasTask !== isTask) return false // 任务性变化时交回 PM 重建视图 + if (checkbox && next.attrs.checked != null) { + checkbox.checked = Boolean(next.attrs.checked) + dom.dataset.checked = String(next.attrs.checked) + } + return true + }, + stopEvent: (event) => (checkbox ? event.target === checkbox : false), + ignoreMutation: (mutation) => mutation.target === dom && mutation.type === 'attributes', + } +} + +export function createListItemViewPlugin(): MilkdownPlugin { + return (ctx) => async () => { + ctx.update(nodeViewCtx, (views) => [ + ...views.filter(([id]) => id !== 'list_item'), + ['list_item', listItemView] as [string, NodeViewConstructor], + ]) + } +} + +// ————————————————— Mermaid 代码块视图(阶段 3) ————————————————— +// code_block 的 language 为 mermaid 时,节点视图渲染 SVG 预览并提供「预览/源码」切换; +// 其他语言维持标准 pre>code 结构。Mermaid 库按需懒加载,只在文档真有图表时才付出体积。 + +interface CodeBlockNode { + type: { name: string } + attrs: { language?: string } + textContent: string +} + +let mermaidSeq = 0 + +const codeBlockView: NodeViewConstructor = (node, _view, _getPos) => { + let current = node as unknown as CodeBlockNode + const isMermaid = () => current.attrs.language === 'mermaid' + + if (!isMermaid()) { + const pre = document.createElement('pre') + const code = document.createElement('code') + if (current.attrs.language) code.className = `language-${current.attrs.language}` + code.spellcheck = false + pre.appendChild(code) + return { + dom: pre, + contentDOM: code, + update: (updated) => { + const next = updated as unknown as CodeBlockNode + if (next.type.name !== 'code_block') return false + if ((next.attrs.language === 'mermaid') !== isMermaid()) return false + current = next + return true + }, + } + } + + let mode: 'preview' | 'source' = 'preview' + let renderTimer: ReturnType | null = null + mermaidSeq += 1 + const renderId = `new-markdown-mermaid-${mermaidSeq}` + + const dom = document.createElement('div') + dom.className = 'mermaid-block' + const head = document.createElement('div') + head.className = 'mermaid-head' + const label = document.createElement('span') + label.textContent = 'Mermaid 图表' + const toggle = document.createElement('button') + toggle.type = 'button' + toggle.textContent = '编辑源码' + head.appendChild(label) + head.appendChild(toggle) + const preview = document.createElement('div') + preview.className = 'mermaid-preview' + preview.contentEditable = 'false' + const pre = document.createElement('pre') + const code = document.createElement('code') + code.spellcheck = false + pre.appendChild(code) + pre.style.display = 'none' + dom.appendChild(head) + dom.appendChild(preview) + dom.appendChild(pre) + + const applyMode = () => { + preview.style.display = mode === 'preview' ? '' : 'none' + pre.style.display = mode === 'source' ? '' : 'none' + toggle.textContent = mode === 'preview' ? '编辑源码' : '查看预览' + } + + const render = async () => { + if (mode !== 'preview') return + const source = current.textContent + try { + const mermaid = (await import('mermaid')).default + mermaid.initialize({ + startOnLoad: false, + theme: document.documentElement.dataset.theme === 'dark' ? 'dark' : 'default', + securityLevel: 'strict', + }) + const { svg } = await mermaid.render(renderId, source) + preview.innerHTML = svg + preview.classList.remove('mermaid-error') + } catch (e) { + preview.textContent = `图表渲染失败:${e instanceof Error ? e.message : String(e)}(可切换到源码修改)` + preview.classList.add('mermaid-error') + } + } + const scheduleRender = () => { + if (renderTimer) clearTimeout(renderTimer) + renderTimer = setTimeout(() => void render(), 250) + } + + toggle.addEventListener('mousedown', (e) => e.preventDefault()) + toggle.addEventListener('click', () => { + mode = mode === 'preview' ? 'source' : 'preview' + applyMode() + if (mode === 'preview') void render() + }) + + applyMode() + scheduleRender() + + return { + dom, + contentDOM: code, + update: (updated) => { + const next = updated as unknown as CodeBlockNode + if (next.type.name !== 'code_block') return false + if ((next.attrs.language === 'mermaid') !== isMermaid()) return false + const changed = next.textContent !== current.textContent + current = next + if (changed) scheduleRender() + return true + }, + stopEvent: (event) => event.target === toggle, + ignoreMutation: (mutation) => preview.contains(mutation.target as Node) || head.contains(mutation.target as Node), + destroy: () => { if (renderTimer) clearTimeout(renderTimer) }, + } +} + +export function createCodeBlockViewPlugin(): MilkdownPlugin { + return (ctx) => async () => { + ctx.update(nodeViewCtx, (views) => [ + ...views.filter(([id]) => id !== 'code_block'), + ['code_block', codeBlockView] as [string, NodeViewConstructor], + ]) + } +} diff --git a/src/editor/paste.ts b/src/editor/paste.ts new file mode 100644 index 0000000..cbb0345 --- /dev/null +++ b/src/editor/paste.ts @@ -0,0 +1,36 @@ +// 纯文本插入:菜单「粘贴」走 Clipboard API 读文本后调用此函数, +// 替代阶段 1 的 execCommand('paste')(WebView2 策略下不可靠)。 +import type { Editor } from '@milkdown/kit/core' +import { editorViewCtx } from '@milkdown/kit/core' + +export function insertPlainText(editor: Editor, text: string): boolean { + if (!text) return false + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + const { from, to } = view.state.selection + view.dispatch(view.state.tr.insertText(text, from, to).scrollIntoView()) + view.focus() + }) + return true +} + +/** 在选区处插入带链接的文本(附件以 Markdown 链接形式落盘,需求 §6.4)。 */ +export function insertLinkText(editor: Editor, text: string, href: string): boolean { + if (!text || !href) return false + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + const schema = view.state.schema + const mark = schema.marks.link?.create({ href }) + if (!mark) return + // 直接 replaceSelectionWith 插入带标记的文本节点会被 ProseMirror 按插入点活动标记归一化而丢标记; + // 正确做法是先把 link 设为 storedMarks 再 insertText,插入后清掉,避免污染后续输入。 + const { from, to } = view.state.selection + const tr = view.state.tr + tr.setStoredMarks([mark]) + tr.insertText(text, from, to) + tr.setStoredMarks([]) + view.dispatch(tr.scrollIntoView()) + view.focus() + }) + return true +} diff --git a/src/editor/plugins.ts b/src/editor/plugins.ts new file mode 100644 index 0000000..755911b --- /dev/null +++ b/src/editor/plugins.ts @@ -0,0 +1,251 @@ +// 编辑器自研 ProseMirror 插件组(阶段 2): +// 1) syntaxReveal —— Typora 式语法标记显隐:仅光标所在块显示 Markdown 标记,其余只呈现排版结果。 +// 实现为纯 Decoration(只影响 DOM,不进文档模型、不进历史、序列化零影响,有自动化测试断言)。 +// 2) codeBlockTab —— 代码块内 Tab 缩进 / Shift+Tab 反缩进(其余位置 Tab 行为不变)。 +import { Plugin, PluginKey } from '@milkdown/kit/prose/state' +import { Decoration, DecorationSet } from '@milkdown/kit/prose/view' +import { $prose } from '@milkdown/kit/utils' +import { commandsCtx } from '@milkdown/kit/core' +import { addRowAfterCommand, goToNextTableCellCommand, goToPrevTableCellCommand } from '@milkdown/kit/preset/gfm' +import { isImeComposing } from '../utils/ime' + +// ————————————————— syntaxReveal ————————————————— + +interface MarkSpec { open: string; close: (attrs: Record) => string } +const MARK_SPECS: Record = { + strong: { open: '**', close: () => '**' }, + emphasis: { open: '*', close: () => '*' }, + inlineCode: { open: '`', close: () => '`' }, + strike_through: { open: '~~', close: () => '~~' }, + link: { open: '[', close: (attrs) => `](${typeof attrs.href === 'string' ? attrs.href : ''})` }, +} + +function markerDom(text: string): HTMLElement { + const span = document.createElement('span') + span.className = 'md-marker' + span.textContent = text + return span +} + +interface PmNodeLike { + type: { name: string } + attrs: Record + isTextblock: boolean + isText?: boolean + text?: string + marks?: { type: { name: string }; attrs: Record }[] + content: { size: number } +} +interface PmSelectionLike { + from: number + to: number + $from: { + depth: number + parent: PmNodeLike + parentOffset: number + start: (depth?: number) => number + before: (depth?: number) => number + node: (depth: number) => PmNodeLike + } +} + +/** 由文档与选区计算标记装饰。导出供测试直接断言。 */ +export function buildRevealDecorations(doc: unknown, selection: unknown): Decoration[] { + const sel = selection as PmSelectionLike + const $from = sel.$from + const parent = $from.parent + if (!parent?.isTextblock) return [] + const decos: Decoration[] = [] + const blockStart = $from.start($from.depth) + + // 标题:光标在标题内时在内容前显示 # 前缀 + if (parent.type.name === 'heading') { + const level = typeof parent.attrs.level === 'number' ? parent.attrs.level : 1 + decos.push(Decoration.widget(blockStart, () => markerDom(`${'#'.repeat(level)} `), { side: -1 })) + } + + // 引用:光标所在段落若处于引用内,显示 > 前缀 + for (let d = 1; d <= $from.depth; d++) { + if ($from.node(d)?.type.name === 'blockquote') { + decos.push(Decoration.widget(blockStart, () => markerDom('> '), { side: -1 })) + break + } + } + + // 行内标记:只揭示与选区相交的文本段的标记(折叠光标落在段内即揭示,含两端边界) + const children = (parent as unknown as { content: { forEach: (fn: (child: PmNodeLike, off: number) => void) => void } }).content + children.forEach((child, off) => { + // 文本子节点的长度是 text.length(其 content 为空 Fragment,size 为 0);非文本内联节点用 nodeSize 口径的 content+边距近似 + const segSize = child.isText ? (child.text?.length ?? 0) : (child.content?.size ?? 0) + 2 + const segStart = blockStart + off + const segEnd = segStart + segSize + if (!child.isText || !child.marks?.length) return + const hit = sel.from < segEnd && sel.to >= segStart || (sel.from >= segStart && sel.from <= segEnd) + if (!hit) return + for (const mark of child.marks) { + const spec = MARK_SPECS[mark.type.name] + if (!spec) continue + decos.push(Decoration.widget(segStart, () => markerDom(spec.open), { side: -1 })) + decos.push(Decoration.widget(segEnd, () => markerDom(spec.close(mark.attrs)), { side: 1 })) + } + }) + void doc + return decos +} + +const revealKey = new PluginKey<{ decos: DecorationSet }>('syntax-reveal') + +export function createSyntaxRevealPlugin() { + return $prose(() => { + // 每个编辑器实例独立的组合状态:IME 组合期间冻结装饰重算,避免干扰组合输入的 DOM。 + const composing = { on: false } + return new Plugin<{ decos: DecorationSet }>({ + key: revealKey, + state: { + init: (_config, state) => ({ + decos: DecorationSet.create(state.doc, buildRevealDecorations(state.doc, state.selection)), + }), + apply: (tr, prev, _oldState, newState) => { + if (composing.on) return prev + if (!tr.docChanged && !tr.selectionSet && !tr.getMeta(revealKey)) return prev + return { decos: DecorationSet.create(newState.doc, buildRevealDecorations(newState.doc, newState.selection)) } + }, + }, + props: { + decorations: (state) => revealKey.getState(state)?.decos ?? DecorationSet.empty, + }, + view: (view) => { + const onStart = () => { composing.on = true } + const onEnd = () => { + composing.on = false + // 组合结束后补一次重算,让标记显隐跟上最终选区 + view.dispatch(view.state.tr.setMeta(revealKey, 'refresh')) + } + view.dom.addEventListener('compositionstart', onStart) + view.dom.addEventListener('compositionend', onEnd) + return { + destroy: () => { + view.dom.removeEventListener('compositionstart', onStart) + view.dom.removeEventListener('compositionend', onEnd) + }, + } + }, + }) + }) +} + +// ————————————————— codeBlockTab ————————————————— + +interface MinimalView { + state: { + selection: { $from: { parent: PmNodeLike & { textContent: string }; parentOffset: number; start: (d?: number) => number; depth: number } } + tr: { + insertText: (text: string, from?: number, to?: number) => unknown + delete: (from: number, to: number) => unknown + } + } + dispatch: (tr: unknown) => void +} + +/** 代码块内缩进/反缩进。返回 true 表示已处理。导出供测试。 */ +export function applyCodeBlockIndent(view: MinimalView, outdent: boolean): boolean { + const { $from } = view.state.selection + if ($from.parent.type.name !== 'code_block') return false + const text = $from.parent.textContent + const offset = $from.parentOffset + const blockStart = $from.start($from.depth) + if (!outdent) { + view.dispatch(view.state.tr.insertText(' ', blockStart + offset)) + return true + } + const lineStart = text.lastIndexOf('\n', Math.max(0, offset - 1)) + 1 + const leading = text.slice(lineStart, lineStart + 2) + const remove = leading.startsWith(' ') ? 2 : leading.startsWith(' ') ? 1 : 0 + if (remove === 0) return true // 已在行首无缩进:吞掉 Tab,避免焦点跳走 + view.dispatch(view.state.tr.delete(blockStart + lineStart, blockStart + lineStart + remove)) + return true +} + +// ————————————————— 表格 Tab 导航(阶段 3) ————————————————— + +interface AncestorLike { + depth: number + node: (d: number) => { type: { name: string } } + before: (d?: number) => number +} + +/** 选区是否在表格单元格内。 */ +export function selectionInTable(selection: { $from: AncestorLike }): boolean { + const $from = selection.$from + for (let d = 1; d <= $from.depth; d++) { + const name = $from.node(d)?.type.name + if (name === 'table_cell' || name === 'table_header') return true + } + return false +} + +/** 当前单元格是否为整表最后一个单元格。 */ +export function isLastTableCell(state: { selection: { $from: AncestorLike }; doc: PmDocLike }): boolean { + const $from = state.selection.$from + let tablePos = -1 + let cellPos = -1 + for (let d = 1; d <= $from.depth; d++) { + const name = $from.node(d)?.type.name + if (name === 'table_cell' || name === 'table_header') cellPos = $from.before(d) + if (name === 'table') tablePos = $from.before(d) + } + if (tablePos < 0 || cellPos < 0) return false + const table = state.doc.nodeAt(tablePos) + if (!table) return false + let total = 0 + let currentIndex = -1 + table.descendants((node: { type: { name: string } }, pos: number) => { + if (node.type.name === 'table_cell' || node.type.name === 'table_header') { + if (tablePos + pos + 1 === cellPos) currentIndex = total + total += 1 + } + return true + }) + return currentIndex === total - 1 +} + +interface PmDocLike { + nodeAt: (pos: number) => { descendants: (fn: (node: { type: { name: string } }, pos: number) => boolean | void) => void } | null +} + +export function createTableTabPlugin() { + return $prose((ctx) => new Plugin({ + props: { + handleKeyDown: (view, event) => { + if (event.key !== 'Tab' || isImeComposing(event)) return false + const selection = view.state.selection as unknown as { $from: AncestorLike } + if (!selectionInTable(selection)) return false + event.preventDefault() + const commands = ctx.get(commandsCtx) as unknown as { call: (k: unknown, p?: unknown) => boolean } + if (event.shiftKey) { + commands.call(goToPrevTableCellCommand.key) + return true + } + if (isLastTableCell(view.state as unknown as { selection: { $from: AncestorLike }; doc: PmDocLike })) { + commands.call(addRowAfterCommand.key) + } + commands.call(goToNextTableCellCommand.key) + return true + }, + }, + })) +} + +export function createCodeBlockTabPlugin() { + return $prose(() => new Plugin({ + props: { + handleKeyDown: (view, event) => { + if (event.key !== 'Tab') return false + if (isImeComposing(event)) return false + const handled = applyCodeBlockIndent(view as unknown as MinimalView, event.shiftKey) + if (handled) event.preventDefault() + return handled + }, + }, + })) +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..aef8763 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,7 @@ +import { createRoot } from 'react-dom/client' +import App from './App' +import 'katex/dist/katex.min.css' +import './styles.css' + +// 不用 StrictMode:开发期双重挂载会重复创建 Milkdown 编辑器(阶段 0 已确认)。 +createRoot(document.getElementById('root')!).render() diff --git a/src/services/platform.ts b/src/services/platform.ts new file mode 100644 index 0000000..9ba4f09 --- /dev/null +++ b/src/services/platform.ts @@ -0,0 +1,141 @@ +// 平台服务层:所有磁盘/对话框访问收口于此。 +// - Tauri 模式:走 Rust 命令(编码探测 + 原子写)与官方 dialog 插件; +// - Web 降级模式(npm run dev 在浏览器里调 UI 时):文件打开用 读入, +// 保存退化为下载。降级仅用于界面调试,UI 状态栏会明确标注当前模式,不冒充桌面能力。 + +export interface ReadResult { + content: string + encoding: string + lineEnding: string + hadBom: boolean +} + +export interface DirEntry { + name: string + path: string + isDir: boolean +} + +export function isTauri(): boolean { + return typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window +} + +async function invoke(cmd: string, args?: Record): Promise { + const { invoke } = await import('@tauri-apps/api/core') + return invoke(cmd, args) +} + +export async function pickOpenFile(): Promise { + if (!isTauri()) return null + const { open } = await import('@tauri-apps/plugin-dialog') + const picked = await open({ + multiple: false, + directory: false, + filters: [ + { name: 'Markdown', extensions: ['md', 'markdown'] }, + { name: '文本文件', extensions: ['txt'] }, + { name: '全部文件', extensions: ['*'] }, + ], + }) + return typeof picked === 'string' ? picked : null +} + +export async function pickSaveFile(defaultName: string): Promise { + if (!isTauri()) return null + const { save } = await import('@tauri-apps/plugin-dialog') + const picked = await save({ + defaultPath: defaultName, + filters: [{ name: 'Markdown', extensions: ['md'] }], + }) + return picked ?? null +} + +export async function pickFolder(): Promise { + if (!isTauri()) return null + const { open } = await import('@tauri-apps/plugin-dialog') + const picked = await open({ multiple: false, directory: true }) + return typeof picked === 'string' ? picked : null +} + +export async function readTextFile(path: string): Promise { + return invoke('read_text_file', { path }) +} + +export async function writeTextFile(path: string, content: string, keepBom: boolean): Promise { + await invoke('write_text_file', { path, content, keepBom }) +} + +export async function listDir(path: string): Promise { + return invoke('list_dir', { path }) +} + +async function pickFileWithFilters(filters: { name: string; extensions: string[] }[]): Promise { + if (!isTauri()) return null + const { open } = await import('@tauri-apps/plugin-dialog') + const picked = await open({ multiple: false, directory: false, filters }) + return typeof picked === 'string' ? picked : null +} + +export function pickImageFile(): Promise { + return pickFileWithFilters([{ name: '图片', extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp'] }]) +} + +export function pickAnyFile(): Promise { + return pickFileWithFilters([{ name: '全部文件', extensions: ['*'] }]) +} + +/** 把外部文件复制进文档资源目录,返回相对路径(阶段 3 图片/附件落盘)。 */ +export async function copyToAssets(source: string, docPath: string): Promise { + return invoke('copy_to_assets', { source, docPath }) +} + +/** 把字节(粘贴/拖入的图片)写入文档资源目录,返回相对路径。 */ +export async function saveBytesToAssets(docPath: string, fileName: string, bytes: number[]): Promise { + return invoke('save_bytes_to_assets', { docPath, fileName, bytes }) +} + +/** Web 降级:选图片并读为 data URL。 */ +export function pickAndReadWebImage(): Promise<{ name: string; dataUrl: string } | null> { + return new Promise((resolve) => { + const input = document.createElement('input') + input.type = 'file' + input.accept = 'image/*' + input.onchange = () => { + const file = input.files?.[0] + if (!file) return resolve(null) + const reader = new FileReader() + reader.onload = () => resolve({ name: file.name, dataUrl: String(reader.result) }) + reader.onerror = () => resolve(null) + reader.readAsDataURL(file) + } + input.oncancel = () => resolve(null) + input.click() + }) +} + +/** Web 降级:选文件并读入文本。返回 null 表示用户取消。 */ +export function pickAndReadWebFile(): Promise<{ name: string; content: string } | null> { + return new Promise((resolve) => { + const input = document.createElement('input') + input.type = 'file' + input.accept = '.md,.markdown,.txt,text/plain,text/markdown' + input.onchange = async () => { + const file = input.files?.[0] + if (!file) return resolve(null) + resolve({ name: file.name, content: await file.text() }) + } + input.oncancel = () => resolve(null) + input.click() + }) +} + +/** Web 降级:把内容作为下载交付(等价于另存为)。 */ +export function downloadTextFile(name: string, content: string): void { + const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = name + a.click() + URL.revokeObjectURL(url) +} diff --git a/src/stores/tabs.ts b/src/stores/tabs.ts new file mode 100644 index 0000000..a94f904 --- /dev/null +++ b/src/stores/tabs.ts @@ -0,0 +1,114 @@ +// 标签页文档会话模型(纯状态 + reducer,单测覆盖)。 +// 每个标签 = 一份 EditorSession:正文 content 与上次保存 savedContent 分离,dirty 由二者比较得出, +// 避免「改回原样仍显示未保存」这类误报。 + +export interface DocTab { + id: string + /** 磁盘路径;未命名文档为 null */ + path: string | null + title: string + content: string + savedContent: string + encoding: string + lineEnding: string + hadBom: boolean +} + +export interface TabsState { + tabs: DocTab[] + activeId: string | null +} + +let seq = 0 +export function nextTabId(): string { + seq += 1 + return `tab-${Date.now().toString(36)}-${seq}` +} + +export function createTab(partial: Partial & { content: string }): DocTab { + return { + id: partial.id ?? nextTabId(), + path: partial.path ?? null, + title: partial.title ?? '未命名', + content: partial.content, + savedContent: partial.savedContent ?? partial.content, + encoding: partial.encoding ?? 'UTF-8', + lineEnding: partial.lineEnding ?? 'LF', + hadBom: partial.hadBom ?? false, + } +} + +export function isDirty(tab: DocTab): boolean { + return tab.content !== tab.savedContent +} + +export type TabsAction = + | { type: 'open'; tab: DocTab } + | { type: 'activate'; id: string } + | { type: 'updateContent'; id: string; content: string } + | { type: 'saved'; id: string; path?: string; title?: string } + | { type: 'close'; id: string } + | { type: 'closeOthers'; id: string } + | { type: 'closeRight'; id: string } + | { type: 'move'; id: string; toIndex: number } + +export function tabsReducer(state: TabsState, action: TabsAction): TabsState { + switch (action.type) { + case 'open': { + // 同一文件已打开则直接激活,不重复建标签 + if (action.tab.path) { + const existing = state.tabs.find((t) => t.path === action.tab.path) + if (existing) return { ...state, activeId: existing.id } + } + return { tabs: [...state.tabs, action.tab], activeId: action.tab.id } + } + case 'activate': + return state.tabs.some((t) => t.id === action.id) ? { ...state, activeId: action.id } : state + case 'updateContent': + return { + ...state, + tabs: state.tabs.map((t) => (t.id === action.id ? { ...t, content: action.content } : t)), + } + case 'saved': + return { + ...state, + tabs: state.tabs.map((t) => + t.id === action.id + ? { ...t, savedContent: t.content, path: action.path ?? t.path, title: action.title ?? t.title } + : t, + ), + } + case 'close': { + const idx = state.tabs.findIndex((t) => t.id === action.id) + if (idx < 0) return state + const tabs = state.tabs.filter((t) => t.id !== action.id) + let activeId = state.activeId + if (state.activeId === action.id) { + const next = tabs[Math.min(idx, tabs.length - 1)] + activeId = next ? next.id : null + } + return { tabs, activeId } + } + case 'closeOthers': + return { tabs: state.tabs.filter((t) => t.id === action.id), activeId: action.id } + case 'closeRight': { + const idx = state.tabs.findIndex((t) => t.id === action.id) + if (idx < 0) return state + return { ...state, tabs: state.tabs.slice(0, idx + 1) } + } + case 'move': { + const idx = state.tabs.findIndex((t) => t.id === action.id) + if (idx < 0 || action.toIndex < 0 || action.toIndex >= state.tabs.length) return state + const tabs = [...state.tabs] + const [moved] = tabs.splice(idx, 1) + tabs.splice(action.toIndex, 0, moved) + return { ...state, tabs } + } + default: + return state + } +} + +export function activeTab(state: TabsState): DocTab | null { + return state.tabs.find((t) => t.id === state.activeId) ?? null +} diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 0000000..c3e216d --- /dev/null +++ b/src/styles.css @@ -0,0 +1,149 @@ +/* new-markdown 阶段 1 样式:应用 UI 主题(CSS 变量)+ 文档排版基础。 + 视觉定调:中性、克制、石板色点缀、适度圆角、无渐变无投影堆叠(docs/04)。 */ +:root { + --bg: #f6f6f4; + --bg-panel: #f0f0ee; + --bg-editor: #ffffff; + --border: #e0e0dc; + --text: #24292f; + --text-dim: #6b7280; + --accent: #43536a; + --accent-weak: #e8ecf1; + --hover: #e9e9e6; + --code-bg: #f4f4f2; +} +html[data-theme='dark'] { + --bg: #2b2b2b; + --bg-panel: #252525; + --bg-editor: #1f1f1f; + --border: #3a3a3a; + --text: #d6d6d3; + --text-dim: #9a9a96; + --accent: #7d93b2; + --accent-weak: #333c48; + --hover: #333333; + --code-bg: #2c2c2c; +} +* { box-sizing: border-box; } +html, body, #root { height: 100%; margin: 0; } +body { font-family: "Segoe UI", "Microsoft YaHei UI", sans-serif; color: var(--text); background: var(--bg); font-size: 14px; } +button { font: inherit; color: inherit; } +.app { display: flex; flex-direction: column; height: 100%; } + +/* 标题栏 */ +.titlebar { display: flex; align-items: center; gap: 9px; height: 38px; padding: 0 0 0 12px; background: var(--bg-panel); border-bottom: 1px solid var(--border); user-select: none; } +.app-mark { background: var(--accent); color: #fff; font-weight: 700; border-radius: 6px; padding: 1px 7px; } +.titlebar-name { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.titlebar-app { color: var(--text-dim); } +.dirty-dot { color: #d08a2d; font-size: 10px; } +.window-controls { margin-left: auto; display: flex; height: 100%; } +.window-controls button { width: 46px; border: 0; background: transparent; cursor: pointer; font-size: 14px; } +.window-controls button:hover { background: var(--hover); } +.window-controls .wc-close:hover { background: #c42b1c; color: #fff; } + +/* 菜单栏 */ +.menubar { display: flex; padding: 2px 6px; background: var(--bg); border-bottom: 1px solid var(--border); user-select: none; position: relative; z-index: 40; } +.menu { position: relative; } +.menu-title { border: 0; background: transparent; padding: 4px 10px; border-radius: 6px; cursor: pointer; font-size: 13px; } +.menu-title:hover, .menu-title.open { background: var(--hover); } +.menu-dropdown { position: absolute; top: 100%; left: 0; min-width: 250px; background: var(--bg-editor); border: 1px solid var(--border); border-radius: 8px; padding: 5px; box-shadow: 0 8px 24px rgba(0,0,0,0.13); } +.menu-item { display: flex; align-items: center; width: 100%; border: 0; background: transparent; padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 13px; text-align: left; } +.menu-item:hover:not(:disabled) { background: var(--accent-weak); } +.menu-item:disabled { color: var(--text-dim); cursor: default; } +.menu-check { width: 18px; flex: none; } +.menu-label { flex: 1; white-space: nowrap; } +.menu-shortcut { color: var(--text-dim); font-size: 12px; margin-left: 24px; } +.menu-divider { height: 1px; background: var(--border); margin: 5px 8px; } + +/* 标签栏 */ +.tabbar { display: flex; align-items: stretch; background: var(--bg-panel); border-bottom: 1px solid var(--border); min-height: 36px; overflow-x: auto; } +.tab { display: flex; align-items: center; gap: 7px; padding: 0 8px 0 14px; font-size: 13px; cursor: pointer; border-right: 1px solid var(--border); white-space: nowrap; color: var(--text-dim); } +.tab.active { background: var(--bg-editor); color: var(--text); box-shadow: inset 0 2px 0 var(--accent); } +.tab-title { max-width: 180px; overflow: hidden; text-overflow: ellipsis; } +.tab-dirty { color: #d08a2d; font-size: 9px; } +.tab-close { border: 0; background: transparent; border-radius: 5px; cursor: pointer; padding: 1px 5px; color: var(--text-dim); } +.tab-close:hover { background: var(--hover); color: var(--text); } +.tab-new { border: 0; background: transparent; padding: 0 12px; cursor: pointer; color: var(--text-dim); font-size: 15px; } +.tab-new:hover { background: var(--hover); } +.context-menu { position: fixed; z-index: 90; background: var(--bg-editor); border: 1px solid var(--border); border-radius: 8px; padding: 5px; box-shadow: 0 8px 24px rgba(0,0,0,0.13); display: flex; flex-direction: column; min-width: 170px; } +.context-menu button { border: 0; background: transparent; text-align: left; padding: 6px 10px; border-radius: 6px; cursor: pointer; font-size: 13px; } +.context-menu button:hover { background: var(--accent-weak); } + +/* 主区域 */ +.main { flex: 1; display: flex; min-height: 0; } +.sidebar { flex: 1; display: flex; flex-direction: column; background: var(--bg-panel); border-right: 1px solid var(--border); min-width: 0; } +.sidebar-tabs { display: flex; gap: 4px; padding: 8px 10px 4px; } +.sidebar-tabs button { flex: 1; border: 0; background: transparent; padding: 5px 0; border-radius: 999px; cursor: pointer; font-size: 13px; color: var(--text-dim); } +.sidebar-tabs button.active { background: var(--accent-weak); color: var(--text); } +.outline, .filetree { overflow-y: auto; padding: 6px 8px 16px; } +.outline-item { display: block; width: 100%; text-align: left; border: 0; background: transparent; padding: 4px 6px; border-radius: 6px; cursor: pointer; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.outline-item:hover { background: var(--hover); } +.sidebar-empty { padding: 14px 12px; font-size: 13px; color: var(--text-dim); line-height: 1.6; } +.sidebar-action, .primary { background: var(--accent); color: #fff; border: 0; border-radius: 7px; padding: 6px 14px; cursor: pointer; } +.filetree-head { display: flex; align-items: center; gap: 6px; padding: 2px 4px 6px; } +.filetree-root { font-weight: 600; font-size: 13px; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.filetree-head button { border: 0; background: transparent; cursor: pointer; border-radius: 5px; color: var(--text-dim); } +.filetree-head button:hover { background: var(--hover); } +.tree-item { display: flex; gap: 5px; width: 100%; text-align: left; border: 0; background: transparent; padding: 3.5px 6px; border-radius: 6px; cursor: pointer; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.tree-item:hover { background: var(--hover); } +.tree-item.active { background: var(--accent-weak); } +.tree-icon { color: var(--text-dim); width: 12px; flex: none; } + +.editor-scroll { flex: 1; overflow-y: auto; background: var(--bg-editor); min-width: 0; } +.editor-host { max-width: 880px; margin: 0 auto; padding: 34px 48px 140px; } +.source-cm { height: 100%; max-width: 980px; margin: 0 auto; } +.source-cm .cm-editor { height: 100%; outline: none; } +.md-marker { color: var(--text-dim); opacity: 0.55; font-size: 0.9em; pointer-events: none; user-select: none; white-space: pre; } +.empty-state { max-width: 520px; margin: 18vh auto 0; text-align: center; color: var(--text-dim); } +.empty-state h2 { color: var(--text); font-weight: 600; } +.empty-state button { margin: 6px; border: 1px solid var(--border); background: var(--bg); border-radius: 7px; padding: 6px 14px; cursor: pointer; } +.empty-state button.primary { background: var(--accent); color: #fff; border-color: transparent; } + +/* 状态栏 */ +.statusbar { display: flex; gap: 16px; align-items: center; height: 26px; padding: 0 12px; background: var(--bg-panel); border-top: 1px solid var(--border); font-size: 12px; color: var(--text-dim); user-select: none; } +.status-right { margin-left: auto; display: flex; gap: 16px; } + +/* 弹窗 */ +.modal-backdrop { position: fixed; inset: 0; background: rgba(20, 22, 26, 0.35); display: flex; align-items: center; justify-content: center; z-index: 100; } +.modal { background: var(--bg-editor); color: var(--text); border-radius: 10px; padding: 20px 22px; width: min(480px, 92vw); max-height: 86vh; overflow-y: auto; box-shadow: 0 16px 48px rgba(0,0,0,0.25); } +.modal h3 { margin: 0 0 10px; font-size: 16px; } +.modal p { line-height: 1.7; font-size: 13.5px; } +.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; } +.modal-actions button { border: 1px solid var(--border); background: var(--bg); border-radius: 7px; padding: 6px 14px; cursor: pointer; } +.modal-actions button.primary { background: var(--accent); color: #fff; border-color: transparent; } +.modal-input { width: 100%; padding: 8px 10px; border: 1px solid var(--border); border-radius: 7px; background: var(--bg); color: var(--text); } +.modal-note { color: var(--text-dim); font-size: 12.5px; } +.shortcuts-table { border-collapse: collapse; width: 100%; font-size: 13px; } +.shortcuts-table td { padding: 5px 6px; border-bottom: 1px solid var(--border); } +.shortcuts-table td:last-child { text-align: right; } +kbd { background: var(--code-bg); border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px; font-family: Consolas, monospace; font-size: 12px; } + +/* ——— 文档排版(基础主题,阶段 5 做完整主题系统) ——— */ +.milkdown .ProseMirror { outline: none; font-size: calc(16.5px * var(--doc-zoom, 1)); line-height: 1.78; color: var(--text); caret-color: var(--accent); } +.milkdown .ProseMirror h1 { font-size: 1.85em; border-bottom: 1px solid var(--border); padding-bottom: 8px; line-height: 1.3; } +.milkdown .ProseMirror h2 { font-size: 1.5em; line-height: 1.35; } +.milkdown .ProseMirror h3 { font-size: 1.25em; } +.milkdown .ProseMirror blockquote { margin-left: 0; padding-left: 14px; border-left: 3px solid var(--accent); color: var(--text-dim); } +.milkdown .ProseMirror code { background: var(--code-bg); border-radius: 6px; padding: 2px 5px; font-family: "Cascadia Code", Consolas, monospace; font-size: 0.88em; } +.milkdown .ProseMirror pre { background: var(--code-bg); border-radius: 8px; padding: 14px 16px; overflow-x: auto; } +.milkdown .ProseMirror pre code { background: transparent; padding: 0; } +.milkdown .ProseMirror table { border-collapse: collapse; } +.milkdown .ProseMirror th, .milkdown .ProseMirror td { border: 1px solid var(--border); padding: 6px 12px; } +.milkdown .ProseMirror img { max-width: 100%; } +.milkdown .ProseMirror a { color: var(--accent); } +.milkdown .ProseMirror hr { border: 0; border-top: 1px solid var(--border); } +.milkdown .ProseMirror li.task-item { list-style: none; display: flex; align-items: flex-start; gap: 2px; margin-left: -1.1em; } +.milkdown .ProseMirror .task-checkbox { margin-top: 0.42em; width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; flex: none; } +.milkdown .ProseMirror li[data-checked='true'] .task-content { color: var(--text-dim); } +.editor-pane-wrap { position: relative; } +.table-toolbar { position: absolute; z-index: 30; display: flex; gap: 2px; align-items: center; background: var(--bg-editor); border: 1px solid var(--border); border-radius: 8px; padding: 3px; box-shadow: 0 6px 18px rgba(0,0,0,0.12); } +.table-toolbar button { border: 0; background: transparent; padding: 4px 8px; border-radius: 6px; cursor: pointer; font-size: 12.5px; white-space: nowrap; } +.table-toolbar button:hover { background: var(--accent-weak); } +.table-toolbar .tt-sep { width: 1px; height: 16px; background: var(--border); margin: 0 3px; } +.mermaid-block { border: 1px solid var(--border); border-radius: 8px; margin: 10px 0; overflow: hidden; } +.mermaid-head { display: flex; align-items: center; justify-content: space-between; padding: 4px 10px; background: var(--code-bg); font-size: 12px; color: var(--text-dim); } +.mermaid-head button { border: 0; background: transparent; cursor: pointer; color: var(--accent); font-size: 12px; padding: 2px 6px; } +.mermaid-preview { padding: 14px; text-align: center; overflow-x: auto; } +.mermaid-preview svg { max-width: 100%; height: auto; } +.mermaid-preview.mermaid-error { color: #b3261e; font-size: 13px; text-align: left; white-space: pre-wrap; } +.mermaid-block pre { margin: 0 !important; border-radius: 0 !important; } diff --git a/src/utils/ime.ts b/src/utils/ime.ts new file mode 100644 index 0000000..b442003 --- /dev/null +++ b/src/utils/ime.ts @@ -0,0 +1,5 @@ +// IME 组合输入判定:组合期间(拼音未上屏)任何快捷键/命令都不得触发。 +// keyCode 229 是浏览器对 IME 处理中按键的传统标记,isComposing 为标准属性,双保险。 +export function isImeComposing(e: { isComposing?: boolean; keyCode?: number }): boolean { + return e.isComposing === true || e.keyCode === 229 +} diff --git a/src/utils/text.ts b/src/utils/text.ts new file mode 100644 index 0000000..1f13538 --- /dev/null +++ b/src/utils/text.ts @@ -0,0 +1,44 @@ +// 文本统计与大纲提取:纯函数,单测覆盖(tests/text.test.ts)。 + +/** 字数:中文按汉字计,英文/数字按词计,标点不计(需求 §10)。代码块是否计入由设置控制,默认计入。 */ +export function countWords(markdown: string, includeCodeBlocks = true): number { + let text = markdown + if (!includeCodeBlocks) text = text.replace(/```[\s\S]*?(```|$)/g, ' ') + const cjk = (text.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) ?? []).length + const words = (text.replace(/[\u4e00-\u9fff\u3400-\u4dbf]/g, ' ').match(/[A-Za-z0-9]+(?:'[A-Za-z]+)?/g) ?? []).length + return cjk + words +} + +export function countChars(markdown: string): number { + return [...markdown].length +} + +export interface OutlineItem { + level: number + text: string + /** 在序列化 Markdown 中的行号(0 基),用于大纲点击定位的近似锚点 */ + line: number +} + +/** 从 Markdown 文本提取大纲。注意跳过代码块内的 # 行。 */ +export function extractOutline(markdown: string): OutlineItem[] { + const items: OutlineItem[] = [] + const lines = markdown.split('\n') + let inFence = false + lines.forEach((raw, i) => { + if (/^\s*(```|~~~)/.test(raw)) inFence = !inFence + if (inFence) return + const m = /^(#{1,6})\s+(.+?)\s*#*\s*$/.exec(raw) + if (m) items.push({ level: m[1].length, text: m[2].trim(), line: i }) + }) + return items +} + +export function baseName(path: string): string { + const normalized = path.replace(/\\/g, '/') + return normalized.split('/').filter(Boolean).pop() ?? path +} + +export function isMarkdownPath(path: string): boolean { + return /\.(md|markdown)$/i.test(path) +} diff --git a/tests/cursorSync.test.ts b/tests/cursorSync.test.ts new file mode 100644 index 0000000..a86d585 --- /dev/null +++ b/tests/cursorSync.test.ts @@ -0,0 +1,35 @@ +import { describe, it, expect } from 'vitest' +import { anchorFromMarkdown, offsetInMarkdown, findBlockIndex } from '../src/editor/cursorSync' + +const MD = '# 标题一行\n\n正文段落内容。\n\n- 列表项甲\n- [ ] 任务项乙\n\n> 引用一句\n' + +describe('光标锚点同步', () => { + it('源码偏移 → 锚点:剥掉标题/列表/引用标记', () => { + const headingOffset = MD.indexOf('标题一行') + 2 + expect(anchorFromMarkdown(MD, headingOffset)).toEqual({ blockText: '标题一行', offsetInBlock: 2 }) + const taskOffset = MD.indexOf('任务项乙') + 1 + expect(anchorFromMarkdown(MD, taskOffset)).toEqual({ blockText: '任务项乙', offsetInBlock: 1 }) + const quoteOffset = MD.indexOf('引用一句') + expect(anchorFromMarkdown(MD, quoteOffset)).toEqual({ blockText: '引用一句', offsetInBlock: 0 }) + }) + + it('锚点 → 源码偏移:往返一致', () => { + for (const text of ['标题一行', '正文段落内容。', '列表项甲', '任务项乙', '引用一句']) { + const start = MD.indexOf(text) + const anchor = anchorFromMarkdown(MD, start + 1) + expect(offsetInMarkdown(MD, anchor)).toBe(start + 1) + } + }) + + it('找不到锚点时回落 0,不抛错', () => { + expect(offsetInMarkdown(MD, { blockText: '不存在的块', offsetInBlock: 3 })).toBe(0) + expect(anchorFromMarkdown('', 10)).toEqual({ blockText: '', offsetInBlock: 0 }) + }) + + it('findBlockIndex 精确优先、子串兜底', () => { + const blocks = ['标题一行', '正文段落内容。', '列表项甲'] + expect(findBlockIndex(blocks, { blockText: '正文段落内容。', offsetInBlock: 0 })).toBe(1) + expect(findBlockIndex(blocks, { blockText: '正文段落', offsetInBlock: 0 })).toBe(1) + expect(findBlockIndex(blocks, { blockText: '没有', offsetInBlock: 0 })).toBe(-1) + }) +}) diff --git a/tests/editor-regression.test.ts b/tests/editor-regression.test.ts new file mode 100644 index 0000000..652f488 --- /dev/null +++ b/tests/editor-regression.test.ts @@ -0,0 +1,60 @@ +// 阶段门禁(架构 §7):阶段 0 的往返稳定性套件在正式工程上必须继续全绿。 +import { describe, it, expect, afterEach } from 'vitest' +import type { Editor } from '@milkdown/kit/core' +import { createMarkdownEditor, getMarkdown, callUndo } from '../src/editor/editor' + +const SAMPLE = `# 标题 + +包含**粗体**与任务: + +- [ ] 待办 +- [x] 完成 + +| 列一 | 列二 | +| :--- | ---: | +| 甲 | 1 | + +\`\`\`ts +const n = 1; +\`\`\` +` + +let editors: Editor[] = [] +afterEach(async () => { + for (const e of editors) { try { await e.destroy() } catch { /* ignore */ } } + editors = [] + document.body.innerHTML = '' +}) + +async function load(md: string): Promise { + const root = document.createElement('div') + document.body.appendChild(root) + const editor = createMarkdownEditor(root, md) + editors.push(editor) + await editor.create() + return editor +} + +describe('编辑器回归(阶段 0 套件)', () => { + it('往返保真且第二轮逐字稳定', async () => { + const once = getMarkdown(await load(SAMPLE)) + expect(once).toContain('**粗体**') + expect(once).toMatch(/-\s\[ \]\s待办/) + expect(once).toMatch(/-\s\[[xX]\]\s完成/) + expect(once).toContain('甲') + const twice = getMarkdown(await load(once)) + expect(twice).toBe(once) + }) + + it('撤销命令仍可用', async () => { + const editor = await load('原文\n') + const { editorViewCtx } = await import('@milkdown/kit/core') + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + view.dispatch(view.state.tr.insertText('X', view.state.doc.content.size)) + }) + expect(getMarkdown(editor)).toContain('X') + callUndo(editor) + expect(getMarkdown(editor)).not.toContain('X') + }) +}) diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 0000000..ff6ef8a --- /dev/null +++ b/tests/setup.ts @@ -0,0 +1,16 @@ +// jsdom 缺失的布局 API 垫片:ProseMirror View 在量测坐标时会调用它们。 +// 只补「不抛错」的最小实现,不参与任何断言逻辑。 +type RectLike = { x: number; y: number; width: number; height: number; top: number; left: number; right: number; bottom: number; toJSON: () => object } +const emptyRect: RectLike = { x: 0, y: 0, width: 0, height: 0, top: 0, left: 0, right: 0, bottom: 0, toJSON: () => ({}) } + +if (typeof Range !== 'undefined') { + Range.prototype.getClientRects = Range.prototype.getClientRects ?? (() => ({ length: 0, item: () => null, [Symbol.iterator]: [][Symbol.iterator] }) as unknown as DOMRectList) + Range.prototype.getBoundingClientRect = Range.prototype.getBoundingClientRect ?? (() => emptyRect as DOMRect) +} +if (typeof Element !== 'undefined') { + Element.prototype.getClientRects = Element.prototype.getClientRects ?? (() => ({ length: 0, item: () => null, [Symbol.iterator]: [][Symbol.iterator] }) as unknown as DOMRectList) + Element.prototype.scrollIntoView = Element.prototype.scrollIntoView ?? (() => undefined) +} +if (typeof document !== 'undefined' && !document.elementFromPoint) { + document.elementFromPoint = () => null +} diff --git a/tests/sourceEditor.test.tsx b/tests/sourceEditor.test.tsx new file mode 100644 index 0000000..8d71d9f --- /dev/null +++ b/tests/sourceEditor.test.tsx @@ -0,0 +1,40 @@ +// 源码模式(CodeMirror 6)冒烟:能挂载、锚点 API 可用、改动经 onChange 回传。 +import { describe, it, expect, afterEach } from 'vitest' +import { createRoot, type Root } from 'react-dom/client' +import { act } from 'react-dom/test-utils' +import SourceEditor, { type SourceEditorApi } from '../src/components/SourceEditor' + +let root: Root | null = null +afterEach(() => { + act(() => root?.unmount()) + root = null + document.body.innerHTML = '' +}) + +describe('SourceEditor', () => { + it('挂载 CodeMirror 并提供锚点/跳行 API', async () => { + const md = '# 标题\n\n正文段落。\n' + let api: SourceEditorApi | null = null + const changes: string[] = [] + const container = document.createElement('div') + document.body.appendChild(container) + root = createRoot(container) + await act(async () => { + root!.render( + changes.push(t)} + onReady={(a) => { api = a }} + />, + ) + }) + expect(container.querySelector('.cm-editor')).not.toBeNull() + expect(api).not.toBeNull() + expect(api!.getAnchor()).toEqual({ blockText: '正文段落。', offsetInBlock: 0 }) + act(() => api!.jumpToLine(0)) + expect(api!.getAnchor()?.blockText).toBe('标题') + }) +}) diff --git a/tests/stage2.test.ts b/tests/stage2.test.ts new file mode 100644 index 0000000..2917fc2 --- /dev/null +++ b/tests/stage2.test.ts @@ -0,0 +1,154 @@ +// 阶段 2 验收:标记显隐装饰、代码块 Tab、任务列表勾选 DOM、列表命令、纯文本插入、IME 守卫判定。 +import { describe, it, expect, afterEach } from 'vitest' +import type { Editor } from '@milkdown/kit/core' +import { editorViewCtx } from '@milkdown/kit/core' +import { TextSelection } from '@milkdown/kit/prose/state' +import { createMarkdownEditor, getMarkdown } from '../src/editor/editor' +import { applyCodeBlockIndent } from '../src/editor/plugins' +import { editorCommands } from '../src/editor/commands' +import { insertPlainText } from '../src/editor/paste' +import { isImeComposing } from '../src/utils/ime' + +let editors: Editor[] = [] +afterEach(async () => { + for (const e of editors) { try { await e.destroy() } catch { /* ignore */ } } + editors = [] + document.body.innerHTML = '' +}) + +async function load(md: string): Promise { + const root = document.createElement('div') + document.body.appendChild(root) + const editor = createMarkdownEditor(root, md) + editors.push(editor) + await editor.create() + return editor +} + +function setSelection(editor: Editor, pos: number) { + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, pos))) + }) +} + +function findTextPos(editor: Editor, text: string): number { + let found = -1 + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + view.state.doc.descendants((node, pos) => { + if (found < 0 && node.isText && node.text?.includes(text)) { + found = pos + node.text.indexOf(text) + } + return found < 0 + }) + }) + return found +} + +function markers(editor: Editor): string[] { + let texts: string[] = [] + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + texts = [...view.dom.querySelectorAll('.md-marker')].map((el) => el.textContent ?? '') + }) + return texts +} + +describe('语法标记显隐', () => { + it('光标在标题内显示 # 前缀,在粗体段内显示 **,移开后消失,且文档序列化不受影响', async () => { + const md = '# 大标题\n\n普通段落里的**粗体字**在这里。\n' + const editor = await load(md) + // 初始选区在文档开头(标题内) + expect(markers(editor).some((t) => t.includes('#'))).toBe(true) + + const boldPos = findTextPos(editor, '粗体字') + expect(boldPos).toBeGreaterThan(0) + setSelection(editor, boldPos + 1) + const shown = markers(editor) + expect(shown).toContain('**') + expect(shown.some((t) => t.includes('#'))).toBe(false) + + // 移到段落末尾的纯文本处,标记应全部隐藏 + const endPos = findTextPos(editor, '在这里') + setSelection(editor, endPos + 2) + expect(markers(editor)).toEqual([]) + + // 装饰不进文档:序列化与原文一致(往返稳定) + expect(getMarkdown(editor)).toBe(md) + }) + + it('光标在引用内显示 > 前缀', async () => { + const editor = await load('前文。\n\n> 引用内容在此。\n') + const pos = findTextPos(editor, '引用内容') + setSelection(editor, pos + 1) + expect(markers(editor)).toContain('> ') + }) +}) + +describe('代码块 Tab', () => { + it('代码块内 Tab 插入两空格,Shift+Tab 去掉', async () => { + const editor = await load('```ts\nconst a = 1;\n```\n') + const pos = findTextPos(editor, 'const') + setSelection(editor, pos) + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + expect(applyCodeBlockIndent(view as never, false)).toBe(true) + }) + expect(getMarkdown(editor)).toContain(' const a = 1;') + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + expect(applyCodeBlockIndent(view as never, true)).toBe(true) + }) + expect(getMarkdown(editor)).toContain('const a = 1;') + expect(getMarkdown(editor)).not.toContain(' const') + }) + + it('普通段落里不处理 Tab', async () => { + const editor = await load('普通段落。\n') + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + expect(applyCodeBlockIndent(view as never, false)).toBe(false) + }) + }) +}) + +describe('任务列表与列表命令', () => { + it('任务列表渲染出可点击 checkbox,点击切换并序列化回 [x]', async () => { + const editor = await load('- [ ] 待办事项\n- [x] 已完成\n') + let firstBox: HTMLInputElement | null = null + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + const boxes = view.dom.querySelectorAll('input[type="checkbox"]') + expect(boxes.length).toBe(2) + expect((boxes[1] as HTMLInputElement).checked).toBe(true) + firstBox = boxes[0] as HTMLInputElement + }) + firstBox!.click() + expect(getMarkdown(editor)).toMatch(/-\s\[[xX]\]\s待办事项/) + expect(getMarkdown(editor)).toMatch(/-\s\[[xX]\]\s已完成/) + }) + + it('段落转无序列表命令生效', async () => { + const editor = await load('变成列表项\n') + setSelection(editor, 2) + editorCommands.bulletList(editor) + expect(getMarkdown(editor)).toContain('- 变成列表项') + }) +}) + +describe('纯文本插入与 IME 守卫', () => { + it('insertPlainText 在选区处插入并可撤销序列保留', async () => { + const editor = await load('前后\n') + setSelection(editor, 2) + expect(insertPlainText(editor, '中间')).toBe(true) + expect(getMarkdown(editor)).toContain('前中间后') + }) + + it('isImeComposing 判定', () => { + expect(isImeComposing({ isComposing: true })).toBe(true) + expect(isImeComposing({ keyCode: 229 })).toBe(true) + expect(isImeComposing({ isComposing: false, keyCode: 13 })).toBe(false) + expect(isImeComposing({})).toBe(false) + }) +}) diff --git a/tests/stage3.test.ts b/tests/stage3.test.ts new file mode 100644 index 0000000..16246ed --- /dev/null +++ b/tests/stage3.test.ts @@ -0,0 +1,190 @@ +// 阶段 3 验收:表格操作、数学公式、Mermaid 视图、脚注/HTML 转正、图片命令、附件链接。 +import { describe, it, expect, afterEach } from 'vitest' +import type { Editor } from '@milkdown/kit/core' +import { editorViewCtx } from '@milkdown/kit/core' +import { TextSelection } from '@milkdown/kit/prose/state' +import { createMarkdownEditor, getMarkdown } from '../src/editor/editor' +import { editorCommands, insertMathBlock, insertMermaidBlock } from '../src/editor/commands' +import { insertLinkText } from '../src/editor/paste' +import { selectionInTable, isLastTableCell } from '../src/editor/plugins' + +let editors: Editor[] = [] +afterEach(async () => { + for (const e of editors) { try { await e.destroy() } catch { /* ignore */ } } + editors = [] + document.body.innerHTML = '' +}) + +async function load(md: string): Promise { + const root = document.createElement('div') + document.body.appendChild(root) + const editor = createMarkdownEditor(root, md) + editors.push(editor) + await editor.create() + return editor +} + +async function roundtrip(md: string): Promise { + const once = getMarkdown(await load(md)) + const twice = getMarkdown(await load(once)) + expect(twice).toBe(once) + return once +} + +function setSelection(editor: Editor, pos: number) { + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, pos))) + }) +} + +function findTextPos(editor: Editor, text: string): number { + let found = -1 + editor.action((ctx) => { + ctx.get(editorViewCtx).state.doc.descendants((node, pos) => { + if (found < 0 && node.isText && node.text?.includes(text)) found = pos + node.text.indexOf(text) + return found < 0 + }) + }) + return found +} + +const TABLE_MD = '| 名称 | 数量 |\n| :--- | ---: |\n| 苹果 | 3 |\n| 香蕉 | 5 |\n' + +describe('表格', () => { + it('插入 3×3 表格命令生成表头与数据行', async () => { + const editor = await load('正文。\n') + setSelection(editor, 2) + editorCommands.insertTable(editor, 3, 3) + const md = getMarkdown(editor) + expect(md).toContain('|') + expect(md.split('\n').filter((l) => l.includes('|')).length).toBeGreaterThanOrEqual(4) + }) + + it('光标在单元格内可判定表格上下文与末格', async () => { + const editor = await load(TABLE_MD) + const pos = findTextPos(editor, '香蕉') + setSelection(editor, pos) + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + expect(selectionInTable(view.state.selection as never)).toBe(true) + // “香蕉”在最后一行第一列,不是末格;其右邻“5”所在格是末格 + expect(isLastTableCell(view.state as never)).toBe(false) + }) + const lastPos = findTextPos(editor, '5') + setSelection(editor, lastPos) + editor.action((ctx) => { + expect(isLastTableCell(ctx.get(editorViewCtx).state as never)).toBe(true) + }) + }) + + it('加行/加列/删列改变结构且往返稳定', async () => { + const editor = await load(TABLE_MD) + setSelection(editor, findTextPos(editor, '苹果')) + editorCommands.addRowAfter(editor) + let md = getMarkdown(editor) + expect(md.split('\n').filter((l) => l.startsWith('|')).length).toBe(5) // 表头+分隔+3 数据行 + editorCommands.addColAfter(editor) + md = getMarkdown(editor) + expect(md.split('\n')[0].split('|').length).toBeGreaterThanOrEqual(5) // 3 列 + editorCommands.deleteCol(editor) + const twice = getMarkdown(await load(getMarkdown(editor))) + expect(twice).toBe(getMarkdown(editor)) + }) + + it('对齐命令改变列对齐并保留到序列化', async () => { + const editor = await load(TABLE_MD) + setSelection(editor, findTextPos(editor, '苹果')) + editorCommands.setAlign(editor, 'center') + const md = getMarkdown(editor) + expect(md).toMatch(/:-+:/) + }) +}) + +describe('数学公式(KaTeX 插件)', () => { + it('行内公式往返保留 LaTeX', async () => { + const once = await roundtrip('质能方程 $E = mc^2$ 是物理学常识。\n') + expect(once).toContain('E = mc^2') + expect(once).toContain('$') + }) + + it('块级公式往返保留', async () => { + const once = await roundtrip('$$\n\\frac{a}{b} + \\sqrt{x}\n$$\n') + expect(once).toContain('\\frac{a}{b}') + expect(once).toContain('$$') + }) + + it('插入公式块命令产出 $$ 块', async () => { + const editor = await load('正文。\n') + setSelection(editor, 2) + insertMathBlock(editor) + expect(getMarkdown(editor)).toContain('$$') + expect(getMarkdown(editor)).toContain('E = mc^2') + }) +}) + +describe('Mermaid 与代码块视图', () => { + it('Mermaid 块渲染出节点视图容器,源码保留', async () => { + const source = '```mermaid\ngraph TD\n A[开始] --> B[结束]\n```\n' + const editor = await load(source) + editor.action((ctx) => { + const view = ctx.get(editorViewCtx) + expect(view.dom.querySelector('.mermaid-block')).not.toBeNull() + }) + expect(getMarkdown(editor)).toContain('graph TD') + }) + + it('普通代码块仍是 pre>code 且内容可序列化', async () => { + const editor = await load('```ts\nconst v = 42;\n```\n') + editor.action((ctx) => { + const code = ctx.get(editorViewCtx).dom.querySelector('pre code') + expect(code?.textContent).toContain('const v = 42;') + }) + expect(getMarkdown(editor)).toContain('const v = 42;') + }) + + it('插入 Mermaid 命令产出 mermaid 代码块', async () => { + const editor = await load('正文。\n') + setSelection(editor, 2) + insertMermaidBlock(editor) + const md = getMarkdown(editor) + expect(md).toContain('```mermaid') + expect(md).toContain('graph TD') + }) +}) + +describe('脚注与 HTML(阶段 0 探针转正)', () => { + it('脚注定义与引用往返稳定', async () => { + const once = await roundtrip('正文带脚注[^1],还有第二个[^note]。\n\n[^1]: 第一条脚注。\n\n[^note]: 第二条脚注。\n') + expect(once).toContain('[^1]') + expect(once).toContain('第一条脚注') + expect(once).toContain('[^note]') + }) + + it('行内与块级 HTML 往返保留', async () => { + const once = await roundtrip('一段下划线文本。\n\n
    原始 HTML 块
    \n') + expect(once).toContain('下划线') + expect(once).toContain('原始 HTML 块') + }) +}) + +describe('图片与附件', () => { + it('图片命令插入相对路径图片并往返保留', async () => { + const editor = await load('看图:\n') + setSelection(editor, 3) + editorCommands.image(editor, '文章.assets/image-1.png', '示意图') + const md = getMarkdown(editor) + expect(md).toContain('文章.assets/image-1.png') + const twice = getMarkdown(await load(md)) + expect(twice).toBe(md) + }) + + it('附件以链接形式插入并往返保留', async () => { + const editor = await load('附件:\n') + setSelection(editor, 3) + expect(insertLinkText(editor, '说明.pdf', '文档.assets/说明.pdf')).toBe(true) + const md = getMarkdown(editor) + expect(md).toContain('说明.pdf') + expect(md).toContain('文档.assets/') + }) +}) diff --git a/tests/tabs.test.ts b/tests/tabs.test.ts new file mode 100644 index 0000000..7d5d9af --- /dev/null +++ b/tests/tabs.test.ts @@ -0,0 +1,53 @@ +import { describe, it, expect } from 'vitest' +import { tabsReducer, createTab, isDirty, type TabsState } from '../src/stores/tabs' + +function stateWith(contents: string[]): TabsState { + const tabs = contents.map((c, i) => createTab({ title: `文档${i + 1}`, content: c })) + return { tabs, activeId: tabs[0]?.id ?? null } +} + +describe('标签页会话模型', () => { + it('同路径文档重复打开只激活已有标签', () => { + const a = createTab({ title: 'a.md', path: '/x/a.md', content: 'A' }) + let s: TabsState = { tabs: [a], activeId: a.id } + s = tabsReducer(s, { type: 'open', tab: createTab({ title: 'a.md', path: '/x/a.md', content: 'A2' }) }) + expect(s.tabs).toHaveLength(1) + expect(s.activeId).toBe(a.id) + }) + + it('dirty 由 content 与 savedContent 比较得出,保存后清除,改回原样也清除', () => { + const t = createTab({ content: '原文' }) + expect(isDirty(t)).toBe(false) + let s: TabsState = { tabs: [t], activeId: t.id } + s = tabsReducer(s, { type: 'updateContent', id: t.id, content: '原文改' }) + expect(isDirty(s.tabs[0])).toBe(true) + s = tabsReducer(s, { type: 'updateContent', id: t.id, content: '原文' }) + expect(isDirty(s.tabs[0])).toBe(false) + s = tabsReducer(s, { type: 'updateContent', id: t.id, content: '新版' }) + s = tabsReducer(s, { type: 'saved', id: t.id }) + expect(isDirty(s.tabs[0])).toBe(false) + expect(s.tabs[0].savedContent).toBe('新版') + }) + + it('关闭活动标签后激活相邻标签;关闭其他/右侧范围正确', () => { + let s = stateWith(['a', 'b', 'c']) + const [t1, t2, t3] = s.tabs + s = tabsReducer(s, { type: 'activate', id: t2.id }) + s = tabsReducer(s, { type: 'close', id: t2.id }) + expect(s.tabs.map((t) => t.id)).toEqual([t1.id, t3.id]) + expect(s.activeId).toBe(t3.id) + s = tabsReducer(s, { type: 'open', tab: createTab({ title: 'd', content: 'd' }) }) + const t4 = s.tabs[2] + s = tabsReducer(s, { type: 'closeRight', id: t1.id }) + expect(s.tabs.map((t) => t.id)).toEqual([t1.id]) + void t4 + }) + + it('拖拽排序 move 到目标下标', () => { + let s = stateWith(['a', 'b', 'c']) + const [t1, , t3] = s.tabs + s = tabsReducer(s, { type: 'move', id: t1.id, toIndex: 2 }) + expect(s.tabs[2].id).toBe(t1.id) + expect(s.tabs[0].id).toBe(t3.id === s.tabs[0].id ? t3.id : s.tabs[0].id) + }) +}) diff --git a/tests/text.test.ts b/tests/text.test.ts new file mode 100644 index 0000000..d742237 --- /dev/null +++ b/tests/text.test.ts @@ -0,0 +1,39 @@ +import { describe, it, expect } from 'vitest' +import { countWords, countChars, extractOutline, baseName, isMarkdownPath } from '../src/utils/text' + +describe('字数统计', () => { + it('中文按字、英文按词、标点不计', () => { + expect(countWords('你好,世界!')).toBe(4) + expect(countWords('hello world, again')).toBe(3) + expect(countWords('中文 mixed 文本 test')).toBe(2 + 1 + 2 + 1) + }) + it('代码块可排除', () => { + const md = '正文一二\n\n```\ncode code code\n```\n' + expect(countWords(md, true)).toBe(4 + 3) + expect(countWords(md, false)).toBe(4) + }) + it('字符数按 Unicode 码点计', () => { + expect(countChars('a你好b')).toBe(4) + }) +}) + +describe('大纲提取', () => { + it('提取层级与行号,跳过代码块内的 # 行', () => { + const md = '# 一级\n\n```\n# 不是标题\n```\n\n## 二级\n正文\n### 三级\n' + const outline = extractOutline(md) + expect(outline.map((o) => o.text)).toEqual(['一级', '二级', '三级']) + expect(outline.map((o) => o.level)).toEqual([1, 2, 3]) + expect(outline[1].line).toBe(6) + }) +}) + +describe('路径工具', () => { + it('Windows 路径取文件名', () => { + expect(baseName('C:\\docs\\笔记\\a.md')).toBe('a.md') + expect(baseName('/home/x/b.md')).toBe('b.md') + }) + it('Markdown 路径判定', () => { + expect(isMarkdownPath('a.MD')).toBe(true) + expect(isMarkdownPath('a.txt')).toBe(false) + }) +}) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1a9ffd0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1 @@ +{"compilerOptions":{"esModuleInterop":true,"isolatedModules":true,"jsx":"react-jsx","lib":["ES2022","DOM","DOM.Iterable"],"module":"ESNext","moduleResolution":"bundler","noEmit":true,"skipLibCheck":true,"strict":true,"target":"ES2022","types":["vitest/globals"]},"include":["src","tests","vite.config.ts","vitest.config.ts"]} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..93e9650 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// Tauri 约定:固定 1420 端口,devUrl 与此对应;src-tauri 变更不触发前端热更新。 +export default defineConfig({ + plugins: [react()], + clearScreen: false, + server: { + port: 1420, + strictPort: true, + watch: { ignored: ['**/src-tauri/**'] }, + }, + build: { target: ['chrome105', 'safari15'] }, +}) diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..7369193 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from 'vitest/config' +export default defineConfig({ + test: { environment: 'jsdom', setupFiles: ['./tests/setup.ts'], testTimeout: 20000 }, +})