From 61d16e6db70d2916a989db8a52ed1920c2b2c2e3 Mon Sep 17 00:00:00 2001 From: WATAHIKI YUTO Date: Sun, 11 Jan 2026 12:29:45 +0900 Subject: [PATCH 1/2] Create MVP --- .gitignore | 24 + eslint.config.js | 31 + index.html | 13 + package-lock.json | 4357 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 36 + public/vite.svg | 1 + src/App.tsx | 859 +++++++++ src/main.tsx | 9 + tsconfig.app.json | 28 + tsconfig.json | 7 + tsconfig.node.json | 26 + vite.config.ts | 7 + 12 files changed, 5398 insertions(+) create mode 100644 .gitignore create mode 100644 eslint.config.js create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/vite.svg create mode 100644 src/App.tsx create mode 100644 src/main.tsx create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..e221991 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,31 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactDom from "eslint-plugin-react-dom"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import reactX from "eslint-plugin-react-x"; +import tseslint from "typescript-eslint"; +import { defineConfig, globalIgnores } from "eslint/config"; + +export default defineConfig([ + globalIgnores(["dist"]), + { + files: ["**/*.{ts,tsx}"], + extends: [ + js.configs.recommended, + tseslint.configs.recommendedTypeChecked, + reactDom.configs.recommended, + reactHooks.configs["recommended-latest"], + reactRefresh.configs.vite, + reactX.configs["recommended-typescript"], + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + project: ["./tsconfig.node.json", "./tsconfig.app.json"], + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]); diff --git a/index.html b/index.html new file mode 100644 index 0000000..0661e71 --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + sentence-structure-diagram-app + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6654b99 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4357 @@ +{ + "name": "sentence-structure-diagram-app", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sentence-structure-diagram-app", + "version": "0.0.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/icons-material": "^7.3.4", + "@mui/material": "^7.3.4", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@types/node": "^24.6.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "eslint": "^9.36.0", + "eslint-plugin-react-dom": "^2.2.2", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "eslint-plugin-react-x": "^2.2.2", + "globals": "^16.4.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.45.0", + "vite": "^7.1.7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@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.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@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.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "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.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint-react/ast": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@eslint-react/ast/-/ast-2.2.2.tgz", + "integrity": "sha512-Zxhfj72xEa6Lc1sxQpLETkOXDmMulR28hbWTJ2a54c0PxTKDAZ+BdOoS0KpRk8zHDc7T9q/Nq/3nvOd5Yah+nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-react/eff": "2.2.2", + "@typescript-eslint/types": "^8.46.1", + "@typescript-eslint/typescript-estree": "^8.46.1", + "@typescript-eslint/utils": "^8.46.1", + "string-ts": "^2.2.1" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@eslint-react/core": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@eslint-react/core/-/core-2.2.2.tgz", + "integrity": "sha512-mHsSWI3/J9rROA786BJdkTodFe/WsvlN/A9laCXN/4XB+4tyaeBMfjhkCt9IffOJlfIYft2rktH8zdbAzozyGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "2.2.2", + "@eslint-react/eff": "2.2.2", + "@eslint-react/shared": "2.2.2", + "@eslint-react/var": "2.2.2", + "@typescript-eslint/scope-manager": "^8.46.1", + "@typescript-eslint/types": "^8.46.1", + "@typescript-eslint/utils": "^8.46.1", + "birecord": "^0.1.1", + "ts-pattern": "^5.8.0" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@eslint-react/eff": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@eslint-react/eff/-/eff-2.2.2.tgz", + "integrity": "sha512-Of0ZFSioeNs3kVuEdRKCCYJxymJ79HUiXOZq/T43zqQmfiJU6rl1JddC0sKfxEZ+nC1fX0DJDYHQbwuzoPr3DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@eslint-react/shared": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@eslint-react/shared/-/shared-2.2.2.tgz", + "integrity": "sha512-MmSO3vUHh3SoO+Pf2qsq4s8NyBBrdE7Cm9ddFmCq8AlFhq37w2OiArkGa1qLTlizPmhpYOoDWlJi1prZVulXiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-react/eff": "2.2.2", + "@typescript-eslint/utils": "^8.46.1", + "ts-pattern": "^5.8.0", + "zod": "^4.1.12" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@eslint-react/var": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@eslint-react/var/-/var-2.2.2.tgz", + "integrity": "sha512-psNsMfCypVaTnBDJyUFtpYb2+02mQ4lHiXN0kdnanAAXKJcDORH/1tw6k4xmv2qJ076kZtblIbhulN75RlJhmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "2.2.2", + "@eslint-react/eff": "2.2.2", + "@typescript-eslint/scope-manager": "^8.46.1", + "@typescript-eslint/types": "^8.46.1", + "@typescript-eslint/utils": "^8.46.1", + "ts-pattern": "^5.8.0" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.1.tgz", + "integrity": "sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", + "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", + "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", + "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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==", + "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.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.4.tgz", + "integrity": "sha512-BIktMapG3r4iXwIhYNpvk97ZfYWTreBBQTWjQKbNbzI64+ULHfYavQEX2w99aSWHS58DvXESWIgbD9adKcUOBw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.4.tgz", + "integrity": "sha512-9n6Xcq7molXWYb680N2Qx+FRW8oT6j/LXF5PZFH3ph9X/Rct0B/BlLAsFI7iL9ySI6LVLuQIVtrLiPT82R7OZw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^7.3.4", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.4.tgz", + "integrity": "sha512-gEQL9pbJZZHT7lYJBKQCS723v1MGys2IFc94COXbUIyCTWa+qC77a7hUax4Yjd5ggEm35dk4AyYABpKKWC4MLw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/core-downloads-tracker": "^7.3.4", + "@mui/system": "^7.3.3", + "@mui/types": "^7.4.7", + "@mui/utils": "^7.3.3", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.1.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^7.3.3", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.3.tgz", + "integrity": "sha512-OJM+9nj5JIyPUvsZ5ZjaeC9PfktmK+W5YaVLToLR8L0lB/DGmv1gcKE43ssNLSvpoW71Hct0necfade6+kW3zQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.3.tgz", + "integrity": "sha512-CmFxvRJIBCEaWdilhXMw/5wFJ1+FT9f3xt+m2pPXhHPeVIbBg9MnMvNSJjdALvnQJMPw8jLhrUtXmN7QAZV2fw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.3.tgz", + "integrity": "sha512-Lqq3emZr5IzRLKaHPuMaLBDVaGvxoh6z7HMWd1RPKawBM5uMRaQ4ImsmmgXWtwJdfZux5eugfDhXJUo2mliS8Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/private-theming": "^7.3.3", + "@mui/styled-engine": "^7.3.3", + "@mui/types": "^7.4.7", + "@mui/utils": "^7.3.3", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.7.tgz", + "integrity": "sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.3.tgz", + "integrity": "sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/types": "^7.4.7", + "@types/prop-types": "^15.7.15", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", + "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", + "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", + "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", + "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", + "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "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/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.8.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.8.1.tgz", + "integrity": "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "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==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", + "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz", + "integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/type-utils": "8.46.1", + "@typescript-eslint/utils": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.46.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.1.tgz", + "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.1.tgz", + "integrity": "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.1", + "@typescript-eslint/types": "^8.46.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.1.tgz", + "integrity": "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.1.tgz", + "integrity": "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.1.tgz", + "integrity": "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1", + "@typescript-eslint/utils": "8.46.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.1.tgz", + "integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.1.tgz", + "integrity": "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.46.1", + "@typescript-eslint/tsconfig-utils": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.1.tgz", + "integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.1.tgz", + "integrity": "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.1", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", + "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.38", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.18", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.18.tgz", + "integrity": "sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/birecord": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/birecord/-/birecord-0.1.1.tgz", + "integrity": "sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==", + "dev": true, + "license": "(MIT OR Apache-2.0)" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "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.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "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/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "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/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "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/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "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/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.237", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", + "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "dev": true, + "license": "ISC" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", + "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.1", + "@eslint/core": "^0.16.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.38.0", + "@eslint/plugin-kit": "^0.4.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-dom": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-dom/-/eslint-plugin-react-dom-2.2.2.tgz", + "integrity": "sha512-0M46zRkB6b4RFLOVYMwrKP/bN0fHTTt+En4k/oDel4iu3cFJtRuEy8+YjtFcf2ab+BS7MJzF1kL0Ye7oA6WcEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "2.2.2", + "@eslint-react/core": "2.2.2", + "@eslint-react/eff": "2.2.2", + "@eslint-react/shared": "2.2.2", + "@eslint-react/var": "2.2.2", + "@typescript-eslint/scope-manager": "^8.46.1", + "@typescript-eslint/types": "^8.46.1", + "@typescript-eslint/utils": "^8.46.1", + "compare-versions": "^6.1.1", + "string-ts": "^2.2.1", + "ts-pattern": "^5.8.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "eslint": "^9.37.0", + "typescript": "^5.9.3" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", + "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-plugin-react-x": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-x/-/eslint-plugin-react-x-2.2.2.tgz", + "integrity": "sha512-YfRSuVttlZoXju1cM/ks8Sp5q7e5izEZXBpPdTnOVEyBu+ioNGwu0b3dfSJ+WYcNHjNdpQD2WHbHcUNlR9qQzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-react/ast": "2.2.2", + "@eslint-react/core": "2.2.2", + "@eslint-react/eff": "2.2.2", + "@eslint-react/shared": "2.2.2", + "@eslint-react/var": "2.2.2", + "@typescript-eslint/scope-manager": "^8.46.1", + "@typescript-eslint/type-utils": "^8.46.1", + "@typescript-eslint/types": "^8.46.1", + "@typescript-eslint/utils": "^8.46.1", + "compare-versions": "^6.1.1", + "is-immutable-type": "^5.0.1", + "string-ts": "^2.2.1", + "ts-api-utils": "^2.1.0", + "ts-pattern": "^5.8.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "eslint": "^9.37.0", + "typescript": "^5.9.3" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "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==", + "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/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-immutable-type": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/is-immutable-type/-/is-immutable-type-5.0.1.tgz", + "integrity": "sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@typescript-eslint/type-utils": "^8.0.0", + "ts-api-utils": "^2.0.0", + "ts-declaration-location": "^1.0.4" + }, + "peerDependencies": { + "eslint": "*", + "typescript": ">=4.7.4" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "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/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "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/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "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/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/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "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/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz", + "integrity": "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "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.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "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/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/react-is": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", + "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-ts": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/string-ts/-/string-ts-2.2.1.tgz", + "integrity": "sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-declaration-location": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", + "dev": true, + "funding": [ + { + "type": "ko-fi", + "url": "https://ko-fi.com/rebeccastevens" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" + } + ], + "license": "BSD-3-Clause", + "dependencies": { + "picomatch": "^4.0.2" + }, + "peerDependencies": { + "typescript": ">=4.0.0" + } + }, + "node_modules/ts-declaration-location/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/ts-pattern": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.8.0.tgz", + "integrity": "sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.1.tgz", + "integrity": "sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.46.1", + "@typescript-eslint/parser": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1", + "@typescript-eslint/utils": "8.46.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/undici-types": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "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/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.1.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", + "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", + "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..64b6982 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "sentence-structure-diagram-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/icons-material": "^7.3.4", + "@mui/material": "^7.3.4", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@types/node": "^24.6.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "eslint": "^9.36.0", + "eslint-plugin-react-dom": "^2.2.2", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "eslint-plugin-react-x": "^2.2.2", + "globals": "^16.4.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.45.0", + "vite": "^7.1.7" + } +} diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..eeee7f0 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,859 @@ +import { + type CSSProperties, + useEffect, + useLayoutEffect, + useMemo, + useRef, + useState, +} from "react"; +import { + AppBar, + Toolbar, + Button, + Box, + Paper, + TextField, + IconButton, + Chip, +} from "@mui/material"; +import UploadFileIcon from "@mui/icons-material/UploadFile"; +import DownloadIcon from "@mui/icons-material/IosShare"; +import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"; +import EditIcon from "@mui/icons-material/ModeEditOutline"; +import DrawIcon from "@mui/icons-material/Draw"; +import LinkIcon from "@mui/icons-material/CallMerge"; +import CloseIcon from "@mui/icons-material/Close"; + +// ================================================== +// Types (explicit, minimal) +// ================================================== + +type Label = "S" | "V" | "O" | "C" | "M"; +type RangeKind = "phrase" | "clause" | "modifier" | "underline"; + +type Range = { id: string; type: RangeKind; start: number; end: number }; +type LabelAnnotation = { id: string; targetId: string; label: Label }; +type Relation = { id: string; fromId: string; toId: string }; + +type DocumentState = { + text: string; + ranges: Range[]; + labels: LabelAnnotation[]; + rels: Relation[]; +}; + +// ================================================== +// Helpers (modern browsers only) +// ================================================== + +const createId = () => crypto.randomUUID(); + +const tokenize = (input: string) => + input.trim() + ? input + .replace(/\s+/g, " ") + .trim() + .match( + /[\u2018\u2019\u201C\u201D"']|[(){}\[\]]|—|–|\/|[.,;:!?]|[A-Za-z]+(?:'[A-Za-z]+)?|\d+|\S/gi + ) ?? [] + : []; +const isPunctuationToken = (token: string) => + /^[.,;:!?(){}\[\]"'—–]$/.test(token) || /^[、。]$/.test(token); + +// Geometry (for underlines/labels/arrows) +type TokenRect = { left: number; right: number; top: number; bottom: number }; +const computeSpanGeometry = ( + tokenRects: (TokenRect | undefined)[], + startIndex: number, + endIndex: number +) => { + const rects = tokenRects + .slice(startIndex, endIndex + 1) + .filter(Boolean) as TokenRect[]; + if (!rects.length) return null; + const leftX = Math.min(...rects.map((r) => r.left)); + const rightX = Math.max(...rects.map((r) => r.right)); + const topY = Math.min(...rects.map((r) => r.top)); + const bottomY = Math.max(...rects.map((r) => r.bottom)); + const EPS = 6; + const segments: { key: number; y: number; x1: number; x2: number }[] = []; + rects.forEach((r) => { + const same = segments.find((L) => Math.abs(L.key - r.top) <= EPS); + if (same) { + same.y = Math.max(same.y, r.bottom); + same.x1 = Math.min(same.x1, r.left); + same.x2 = Math.max(same.x2, r.right); + } else { + segments.push({ key: r.top, y: r.bottom, x1: r.left, x2: r.right }); + } + }); + segments.sort((a, b) => a.key - b.key); + return { + midX: (leftX + rightX) / 2, + topY, + botY: bottomY, + segs: segments.map((L) => ({ y: L.y, x1: L.x1, x2: L.x2 })), + } as const; +}; +const buildArrowPath = (x1: number, y1: number, x2: number, y2: number) => { + const span = Math.max(1, Math.abs(x2 - x1)); + const lift = 18 + Math.min(48, span * 0.35); + const apexY = Math.min(y1, y2) - lift; + return { + d: `M ${x1},${y1} C ${x1},${apexY} ${x2},${apexY} ${x2},${y2}`, + midX: (x1 + x2) / 2, + midY: apexY, + }; +}; + +// ================================================== +// Component: header + canvas (first public release) +// ================================================== + +export default function App() { + // View mode + const [viewMode, setViewMode] = useState<"edit" | "annotate">("annotate"); + + // Document state + const [documentState, setDocumentState] = useState({ + text: "When he arrived, the teacher quickly explained the rules to the students.", + ranges: [], + labels: [], + rels: [], + }); + + // Selection / active range / pending relation + const [activeRangeId, setActiveRangeId] = useState(null); + const [pendingRelationFromId, setPendingRelationFromId] = useState< + string | null + >(null); + const [dragAnchorIndex, setDragAnchorIndex] = useState(null); + const [dragFocusIndex, setDragFocusIndex] = useState(null); + const selection = useMemo( + () => + dragAnchorIndex == null || dragFocusIndex == null + ? null + : { + start: Math.min(dragAnchorIndex, dragFocusIndex), + end: Math.max(dragAnchorIndex, dragFocusIndex), + }, + [dragAnchorIndex, dragFocusIndex] + ); + + // Tokens & rects + const tokenList = useMemo( + () => tokenize(documentState.text), + [documentState.text] + ); + const canvasRef = useRef(null); + const tokenRefs = useRef<(HTMLSpanElement | null)[]>([]); + const [tokenRects, setTokenRects] = useState<(TokenRect | undefined)[]>([]); + + const measureTokenRects = () => { + const root = canvasRef.current; + if (!root) return; + const rootBox = root.getBoundingClientRect(); + setTokenRects( + tokenList.map((_, i) => { + const el = tokenRefs.current[i]; + if (!el) return undefined; + const b = el.getBoundingClientRect(); + return { + left: b.left - rootBox.left, + right: b.right - rootBox.left, + top: b.top - rootBox.top, + bottom: b.bottom - rootBox.top, + } as TokenRect; + }) + ); + }; + + useLayoutEffect(() => { + if (viewMode === "annotate") measureTokenRects(); + }, [ + viewMode, + tokenList.length, + documentState.ranges.length, + documentState.labels.length, + documentState.rels.length, + ]); + useEffect(() => { + const on = () => measureTokenRects(); + window.addEventListener("resize", on); + return () => window.removeEventListener("resize", on); + }, []); + useEffect(() => { + if (!canvasRef.current) return; + const ro = new ResizeObserver(() => measureTokenRects()); + ro.observe(canvasRef.current); + return () => ro.disconnect(); + }, []); + + // Helpers + const snapToNearestNonPunctuation = (index: number) => { + if (!isPunctuationToken(tokenList[index] ?? "")) return index; + for (let j = index - 1; j >= 0 && index - j <= 6; j--) + if (!isPunctuationToken(tokenList[j])) return j; + for (let j = index + 1; j < tokenList.length && j - index <= 6; j++) + if (!isPunctuationToken(tokenList[j])) return j; + return index; + }; + const findTopmostRangeAtToken = (index: number) => { + const hit = documentState.ranges.filter( + (r) => index >= r.start && index <= r.end + ); + return hit.length ? hit[hit.length - 1] : null; + }; + const computeToolbarAnchor = ( + start: number, + end: number, + placeAbove: boolean + ) => { + const rects = tokenRects + .slice(start, end + 1) + .filter(Boolean) as TokenRect[]; + if (!rects.length) return null; + const left = Math.min(...rects.map((r) => r.left)); + const right = Math.max(...rects.map((r) => r.right)); + const top = Math.min(...rects.map((r) => r.top)); + const bottom = Math.max(...rects.map((r) => r.bottom)); + return { + x: (left + right) / 2, + y: placeAbove ? Math.max(0, top - 36) : bottom + 10, + }; + }; + + // Bracket markers for non-underline ranges + const openingBrackets = useMemo(() => { + const map: Record = {}; + for (let i = 0; i < tokenList.length; i++) map[i] = []; + documentState.ranges.forEach((range) => { + if (range.type !== "underline") + map[range.start].push( + range.type === "phrase" ? "<" : range.type === "clause" ? "{" : "(" + ); + }); + return map; + }, [documentState.ranges, tokenList.length]); + const closingBrackets = useMemo(() => { + const map: Record = {}; + for (let i = 0; i < tokenList.length; i++) map[i] = []; + documentState.ranges.forEach((range) => { + if (range.type !== "underline") + map[range.end].push( + range.type === "phrase" ? ">" : range.type === "clause" ? "}" : ")" + ); + }); + return map; + }, [documentState.ranges, tokenList.length]); + + // Mutations + const createRange = (type: RangeKind) => { + if (!selection) return; + const id = createId(); + setDocumentState((v) => ({ + ...v, + ranges: [ + ...v.ranges, + { id, type, start: selection.start, end: selection.end }, + ], + })); + setActiveRangeId(id); + setDragAnchorIndex(null); + setDragFocusIndex(null); + }; + const addLabelToActiveRange = (label: Label) => { + if (!activeRangeId) return; + setDocumentState((v) => ({ + ...v, + labels: [...v.labels, { id: createId(), targetId: activeRangeId, label }], + })); + }; + const clearAllAnnotations = () => { + setDocumentState((v) => ({ ...v, ranges: [], labels: [], rels: [] })); + setActiveRangeId(null); + setPendingRelationFromId(null); + setDragAnchorIndex(null); + setDragFocusIndex(null); + }; + const startRelation = () => { + if (activeRangeId) setPendingRelationFromId(activeRangeId); + }; + const cancelRelation = () => setPendingRelationFromId(null); + const commitRelation = (toId: string) => { + if (!pendingRelationFromId || pendingRelationFromId === toId) + return cancelRelation(); + setDocumentState((v) => ({ + ...v, + rels: [ + ...v.rels, + { id: createId(), fromId: pendingRelationFromId, toId }, + ], + })); + cancelRelation(); + }; + const deleteActiveRange = () => { + if (!activeRangeId) return; + setDocumentState((v) => ({ + ...v, + labels: v.labels.filter((l) => l.targetId !== activeRangeId), + rels: v.rels.filter( + (r) => r.fromId !== activeRangeId && r.toId !== activeRangeId + ), + ranges: v.ranges.filter((r) => r.id !== activeRangeId), + })); + setActiveRangeId(null); + }; + + // I/O (pure JSON; ignore legacy fields if present) + const exportJSON = () => { + const blob = new Blob([JSON.stringify(documentState, null, 2)], { + type: "application/json", + }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = "annotation.json"; + a.click(); + URL.revokeObjectURL(url); + }; + const importJSON = (file: File) => { + const reader = new FileReader(); + reader.onload = () => { + try { + const raw = JSON.parse( + String(reader.result) + ) as Partial & { version?: unknown }; + const next: DocumentState = { + text: raw.text ?? "", + ranges: Array.isArray(raw.ranges) ? (raw.ranges) : [], + labels: Array.isArray(raw.labels) + ? (raw.labels) + : [], + rels: Array.isArray(raw.rels) ? (raw.rels) : [], + }; + setDocumentState(next); + setActiveRangeId(null); + setPendingRelationFromId(null); + setDragAnchorIndex(null); + setDragFocusIndex(null); + requestAnimationFrame(measureTokenRects); + } catch { + alert("インポートに失敗しました"); + } + }; + reader.readAsText(file); + }; + + // Derivations + const selectionAnchor = selection + ? computeToolbarAnchor(selection.start, selection.end, false) + : null; + const activeAnchor = activeRangeId + ? (() => { + const r = documentState.ranges.find((x) => x.id === activeRangeId); + return r ? computeToolbarAnchor(r.start, r.end, true) : null; + })() + : null; + const canvasHeight = canvasRef.current?.getBoundingClientRect().height || 0; + + const relationShapes = useMemo( + () => + documentState.rels + .map((rel, index) => { + const from = documentState.ranges.find((x) => x.id === rel.fromId); + const to = documentState.ranges.find((x) => x.id === rel.toId); + if (!from || !to) return null; + const fg = computeSpanGeometry(tokenRects, from.start, from.end); + const tg = computeSpanGeometry(tokenRects, to.start, to.end); + if (!fg || !tg) return null; + const lift = 6 * (index % 3); + const { d, midX, midY } = buildArrowPath( + fg.midX, + fg.topY - 2 - lift, + tg.midX, + tg.topY - 2 - lift + ); + return { id: rel.id, d, midX, midY }; + }) + .filter(Boolean) as { + id: string; + d: string; + midX: number; + midY: number; + }[], + [documentState.rels, documentState.ranges, tokenRects] + ); + + return ( + + + + Annotation + + + + + + + + + + + + + + + {viewMode === "edit" ? ( + + setDocumentState((v) => ({ ...v, text: e.target.value })) + } + placeholder="ここに英文を編集" + /> + ) : ( + + {/* Arrows (non-interactive SVG) */} + + + + + + + {relationShapes.map((shape) => ( + + ))} + + + {/* Arrow delete buttons (HTML) */} + + {relationShapes.map((shape) => ( + + setDocumentState((v) => ({ + ...v, + rels: v.rels.filter((x) => x.id !== shape.id), + })) + } + > + × + + ))} + + + {/* Tokens with bracket markers */} + + {tokenList.map((tokenText, tokenIndex) => { + const inSelection = !!( + selection && + tokenIndex >= selection.start && + tokenIndex <= selection.end && + !isPunctuationToken(tokenText) + ); + const inActiveRange = !!( + activeRangeId && + documentState.ranges.find( + (r) => + r.id === activeRangeId && + tokenIndex >= r.start && + tokenIndex <= r.end + ) + ); + const tokenStyle: CSSProperties = { + position: "relative", + display: "inline-block", + padding: "0 8px", + borderRadius: 8, + marginBottom: 12, + userSelect: "none", + cursor: !isPunctuationToken(tokenText) + ? "pointer" + : "default", + }; + if (inSelection) { + tokenStyle.outline = "2px solid rgba(99,102,241,.6)"; + (tokenStyle as any).background = "rgba(238,242,255,1)"; + } else if (inActiveRange) { + tokenStyle.outline = "2px solid rgba(34,197,94,.6)"; + } + return ( + + {openingBrackets[tokenIndex]?.length ? ( + + {openingBrackets[tokenIndex].join("")} + + ) : null} + + (tokenRefs.current[tokenIndex] = el)} + style={tokenStyle} + onMouseDown={() => { + const j = snapToNearestNonPunctuation(tokenIndex); + setDragAnchorIndex(j); + setDragFocusIndex(j); + }} + onMouseEnter={(e) => { + if (dragAnchorIndex !== null && (e.buttons & 1) === 1) + setDragFocusIndex( + snapToNearestNonPunctuation(tokenIndex) + ); + }} + onMouseUp={() => { + if (dragAnchorIndex !== null) + setDragFocusIndex( + snapToNearestNonPunctuation(tokenIndex) + ); + }} + onClick={() => { + const r = findTopmostRangeAtToken(tokenIndex); + if (!r) { + setActiveRangeId(null); + setPendingRelationFromId(null); + return; + } + if (pendingRelationFromId) commitRelation(r.id); + else setActiveRangeId(r.id); + }} + > + {tokenText} + + + {closingBrackets[tokenIndex]?.length ? ( + + {closingBrackets[tokenIndex].join("")} + + ) : null} + + ); + })} + + + {/* Selection toolbar (pill) */} + {selection && selectionAnchor && ( + + + createRange("phrase")} + /> + createRange("clause")} + /> + createRange("modifier")} + /> + createRange("underline")} + /> + + + )} + + {/* Active toolbar (pill) */} + {activeRangeId && activeAnchor && !selection && ( + + + {(["S", "V", "O", "C", "M"] as Label[]).map((L) => ( + addLabelToActiveRange(L)} + /> + ))} + {!pendingRelationFromId && ( + } + label="矢印" + onClick={startRelation} + /> + )} + {pendingRelationFromId && ( + } + label="キャンセル" + onClick={cancelRelation} + /> + )} + + + + )} + + {/* Underlines + Labels */} + + {documentState.ranges + .filter((r) => r.type === "underline") + .flatMap((range) => { + const g = computeSpanGeometry( + tokenRects, + range.start, + range.end + ); + if (!g) return []; + return g.segs.map((seg, idx) => ( + + )); + })} + + + + {documentState.labels.map((labelAnno) => { + const range = documentState.ranges.find( + (r) => r.id === labelAnno.targetId + ); + if (!range) return null; + const g = computeSpanGeometry( + tokenRects, + range.start, + range.end + ); + if (!g) return null; + return ( + + {labelAnno.label} + + ); + })} + + + )} + + + + + Mode: {viewMode} + + + Tokens: {tokenList.length} + + + Ranges: {documentState.ranges.length} + + + Labels: {documentState.labels.length} + + + Rels: {documentState.rels.length} + + + + + ); +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..4aff025 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,9 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..a9b5a59 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..8a67f62 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..0e43ae8 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}); From e8e58b08d51ccb564ff7976819ab72cca35ac502 Mon Sep 17 00:00:00 2001 From: WATAHIKI YUTO Date: Sun, 11 Jan 2026 12:35:01 +0900 Subject: [PATCH 2/2] Create first version --- .github/workflows/ci.yml | 50 + .github/workflows/deploy.yml | 57 + .gitignore | 24 +- .nvmrc | 1 + .prettierrc | 1 + package-lock.json | 3950 +++++++++++++---- package.json | 48 +- packages/backend/.env.sample | 3 + packages/backend/.gitignore | 2 + packages/backend/_app.ts | 25 + ...enerate-simplified-annotation-by-gemini.ts | 43 + packages/backend/index.ts | 22 + packages/backend/package.json | 28 + packages/backend/trpc.ts | 13 + packages/backend/tsconfig.json | 44 + packages/evaluation/.env.sample | 9 + packages/evaluation/.gitignore | 4 + packages/evaluation/calculate-metrics.ts | 286 ++ packages/evaluation/examples.ts | 718 +++ packages/evaluation/generate-by-gemini.ts | 159 + packages/evaluation/generate-by-openai.ts | 158 + packages/evaluation/generate-metrics.ts | 652 +++ ...erate-sentence-structure-data-by-gemini.ts | 94 + ...nerate-sentence-structure-data-by-llama.ts | 51 + ...erate-sentence-structure-data-by-openai.ts | 95 + packages/evaluation/index.ts | 5 + packages/evaluation/llmConfigurations.ts | 110 + packages/evaluation/package.json | 24 + packages/evaluation/prompt.ts | 121 + .../show-differences-by-json-patch.ts | 40 + packages/evaluation/tsconfig.json | 44 + packages/frontend/.env | 1 + packages/frontend/.gitignore | 24 + .../frontend/eslint.config.js | 12 +- index.html => packages/frontend/index.html | 2 +- packages/frontend/package.json | 42 + {public => packages/frontend/public}/vite.svg | 0 packages/frontend/src/App.tsx | 11 + packages/frontend/src/main.tsx | 9 + .../frontend/src/pages/components/AppBar.tsx | 148 + .../components/ConfirmClearAllDialog.tsx | 44 + .../ConfirmClearAnnotationsDialog.tsx | 35 + .../src/pages/components/ExportDialog.tsx | 494 +++ .../SentenceStructureDiagramAnnotator.tsx | 296 ++ .../components/SentenceStructureEditor.tsx | 642 +++ .../pages/contexts/ConfigurationsProvider.tsx | 72 + .../contexts/InteractionStateProvider.tsx | 1229 +++++ .../SentenceStructureDataProvider.tsx | 82 + packages/frontend/src/pages/index.tsx | 16 + .../src/pages/utils/measure-text-width.ts | 9 + packages/frontend/src/utils/trpc.ts | 15 + .../frontend/tsconfig.app.json | 0 .../frontend/tsconfig.json | 0 .../frontend/tsconfig.node.json | 0 .../frontend/vite.config.ts | 1 + packages/sentence-structure-data/.gitignore | 1 + packages/sentence-structure-data/format.ts | 281 ++ packages/sentence-structure-data/index.ts | 47 + .../sentence-structure-data/operations.ts | 559 +++ packages/sentence-structure-data/package.json | 19 + packages/sentence-structure-data/schema.ts | 353 ++ .../simplified-schema.ts | 219 + .../sentence-structure-data/tokenize-text.ts | 25 + .../sentence-structure-data/tsconfig.json | 44 + .../.gitignore | 1 + .../default-configurations.ts | 26 + .../format.ts | 22 + .../index.ts | 9 + .../package.json | 19 + .../schema.ts | 51 + .../tsconfig.json | 44 + .../.gitignore | 1 + .../extract-position.ts | 74 + .../generate.ts | 172 + .../sentence-structure-diagram-data/index.ts | 2 + .../package.json | 21 + .../resolve-configurations.ts | 300 ++ .../tsconfig.json | 44 + .../sentence-structure-diagram-data/types.ts | 48 + .../sentence-structure-diagram-svg/.gitignore | 1 + .../SentenceStructureDiagram.tsx | 142 + .../generate.ts | 28 + .../sentence-structure-diagram-svg/index.ts | 1 + .../package.json | 22 + .../tsconfig.json | 44 + .../.gitignore | 1 + .../constants.ts | 4 + ...-linear-sentence-structure-diagram-tree.ts | 268 ++ ...uctured-sentence-structure-diagram-tree.ts | 382 ++ .../create-tree.ts | 26 + .../sentence-structure-diagram-tree/index.ts | 9 + .../package.json | 19 + .../tsconfig.json | 44 + .../sentence-structure-diagram-tree/types.ts | 75 + packages/sentence-structure-tree/.gitignore | 1 + .../sentence-structure-tree/create-tree.ts | 299 ++ packages/sentence-structure-tree/index.ts | 9 + packages/sentence-structure-tree/package.json | 17 + .../sentence-structure-tree/tsconfig.json | 44 + packages/sentence-structure-tree/types.ts | 53 + render.yaml | 13 + src/App.tsx | 859 ---- src/main.tsx | 9 - 103 files changed, 12900 insertions(+), 1917 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/deploy.yml create mode 100644 .nvmrc create mode 100644 .prettierrc create mode 100644 packages/backend/.env.sample create mode 100644 packages/backend/.gitignore create mode 100644 packages/backend/_app.ts create mode 100644 packages/backend/generate-simplified-annotation-by-gemini.ts create mode 100644 packages/backend/index.ts create mode 100644 packages/backend/package.json create mode 100644 packages/backend/trpc.ts create mode 100644 packages/backend/tsconfig.json create mode 100644 packages/evaluation/.env.sample create mode 100644 packages/evaluation/.gitignore create mode 100644 packages/evaluation/calculate-metrics.ts create mode 100644 packages/evaluation/examples.ts create mode 100644 packages/evaluation/generate-by-gemini.ts create mode 100644 packages/evaluation/generate-by-openai.ts create mode 100644 packages/evaluation/generate-metrics.ts create mode 100644 packages/evaluation/generate-sentence-structure-data-by-gemini.ts create mode 100644 packages/evaluation/generate-sentence-structure-data-by-llama.ts create mode 100644 packages/evaluation/generate-sentence-structure-data-by-openai.ts create mode 100644 packages/evaluation/index.ts create mode 100644 packages/evaluation/llmConfigurations.ts create mode 100644 packages/evaluation/package.json create mode 100644 packages/evaluation/prompt.ts create mode 100644 packages/evaluation/show-differences-by-json-patch.ts create mode 100644 packages/evaluation/tsconfig.json create mode 100644 packages/frontend/.env create mode 100644 packages/frontend/.gitignore rename eslint.config.js => packages/frontend/eslint.config.js (56%) rename index.html => packages/frontend/index.html (81%) create mode 100644 packages/frontend/package.json rename {public => packages/frontend/public}/vite.svg (100%) create mode 100644 packages/frontend/src/App.tsx create mode 100644 packages/frontend/src/main.tsx create mode 100644 packages/frontend/src/pages/components/AppBar.tsx create mode 100644 packages/frontend/src/pages/components/ConfirmClearAllDialog.tsx create mode 100644 packages/frontend/src/pages/components/ConfirmClearAnnotationsDialog.tsx create mode 100644 packages/frontend/src/pages/components/ExportDialog.tsx create mode 100644 packages/frontend/src/pages/components/SentenceStructureDiagramAnnotator.tsx create mode 100644 packages/frontend/src/pages/components/SentenceStructureEditor.tsx create mode 100644 packages/frontend/src/pages/contexts/ConfigurationsProvider.tsx create mode 100644 packages/frontend/src/pages/contexts/InteractionStateProvider.tsx create mode 100644 packages/frontend/src/pages/contexts/SentenceStructureDataProvider.tsx create mode 100644 packages/frontend/src/pages/index.tsx create mode 100644 packages/frontend/src/pages/utils/measure-text-width.ts create mode 100644 packages/frontend/src/utils/trpc.ts rename tsconfig.app.json => packages/frontend/tsconfig.app.json (100%) rename tsconfig.json => packages/frontend/tsconfig.json (100%) rename tsconfig.node.json => packages/frontend/tsconfig.node.json (100%) rename vite.config.ts => packages/frontend/vite.config.ts (81%) create mode 100644 packages/sentence-structure-data/.gitignore create mode 100644 packages/sentence-structure-data/format.ts create mode 100644 packages/sentence-structure-data/index.ts create mode 100644 packages/sentence-structure-data/operations.ts create mode 100644 packages/sentence-structure-data/package.json create mode 100644 packages/sentence-structure-data/schema.ts create mode 100644 packages/sentence-structure-data/simplified-schema.ts create mode 100644 packages/sentence-structure-data/tokenize-text.ts create mode 100644 packages/sentence-structure-data/tsconfig.json create mode 100644 packages/sentence-structure-diagram-configurations/.gitignore create mode 100644 packages/sentence-structure-diagram-configurations/default-configurations.ts create mode 100644 packages/sentence-structure-diagram-configurations/format.ts create mode 100644 packages/sentence-structure-diagram-configurations/index.ts create mode 100644 packages/sentence-structure-diagram-configurations/package.json create mode 100644 packages/sentence-structure-diagram-configurations/schema.ts create mode 100644 packages/sentence-structure-diagram-configurations/tsconfig.json create mode 100644 packages/sentence-structure-diagram-data/.gitignore create mode 100644 packages/sentence-structure-diagram-data/extract-position.ts create mode 100644 packages/sentence-structure-diagram-data/generate.ts create mode 100644 packages/sentence-structure-diagram-data/index.ts create mode 100644 packages/sentence-structure-diagram-data/package.json create mode 100644 packages/sentence-structure-diagram-data/resolve-configurations.ts create mode 100644 packages/sentence-structure-diagram-data/tsconfig.json create mode 100644 packages/sentence-structure-diagram-data/types.ts create mode 100644 packages/sentence-structure-diagram-svg/.gitignore create mode 100644 packages/sentence-structure-diagram-svg/SentenceStructureDiagram.tsx create mode 100644 packages/sentence-structure-diagram-svg/generate.ts create mode 100644 packages/sentence-structure-diagram-svg/index.ts create mode 100644 packages/sentence-structure-diagram-svg/package.json create mode 100644 packages/sentence-structure-diagram-svg/tsconfig.json create mode 100644 packages/sentence-structure-diagram-tree/.gitignore create mode 100644 packages/sentence-structure-diagram-tree/constants.ts create mode 100644 packages/sentence-structure-diagram-tree/create-linear-sentence-structure-diagram-tree.ts create mode 100644 packages/sentence-structure-diagram-tree/create-structured-sentence-structure-diagram-tree.ts create mode 100644 packages/sentence-structure-diagram-tree/create-tree.ts create mode 100644 packages/sentence-structure-diagram-tree/index.ts create mode 100644 packages/sentence-structure-diagram-tree/package.json create mode 100644 packages/sentence-structure-diagram-tree/tsconfig.json create mode 100644 packages/sentence-structure-diagram-tree/types.ts create mode 100644 packages/sentence-structure-tree/.gitignore create mode 100644 packages/sentence-structure-tree/create-tree.ts create mode 100644 packages/sentence-structure-tree/index.ts create mode 100644 packages/sentence-structure-tree/package.json create mode 100644 packages/sentence-structure-tree/tsconfig.json create mode 100644 packages/sentence-structure-tree/types.ts create mode 100644 render.yaml delete mode 100644 src/App.tsx delete mode 100644 src/main.tsx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..da196c0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +jobs: + format: + name: Format + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: npm + + - name: Install Packages + run: npm ci + shell: bash + + - name: Prettier + run: npm run format:check + shell: bash + + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: npm + + - name: Install Packages + run: npm ci + shell: bash + + - name: Build + run: npm run build + shell: bash diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..af87033 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,57 @@ +name: Deploy + +on: + push: + branches: + - main + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: npm + + - name: Install Packages + run: npm ci + shell: bash + + - name: Build + env: + BASE_URL: "/${{ github.event.repository.name }}/" + VITE_API_ENDPOINT: ${{ vars.VITE_API_ENDPOINT }} + run: npm run build + shell: bash + + - name: Upload artifact + uses: actions/upload-pages-artifact@v4 + with: + path: ./packages/frontend/dist + + deploy: + name: Deploy + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index a547bf3..68b21f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,2 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea +/node_modules .DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/package-lock.json b/package-lock.json index 6654b99..fb54c4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,35 +1,25 @@ { "name": "sentence-structure-diagram-app", - "version": "0.0.0", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sentence-structure-diagram-app", - "version": "0.0.0", - "dependencies": { - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.1", - "@mui/icons-material": "^7.3.4", - "@mui/material": "^7.3.4", - "react": "^19.1.1", - "react-dom": "^19.1.1" - }, + "version": "0.1.0", + "workspaces": [ + "packages/backend", + "packages/frontend", + "packages/sentence-structure-data", + "packages/sentence-structure-diagram-data", + "packages/sentence-structure-diagram-svg", + "packages/evaluation", + "packages/sentence-structure-diagram-configurations", + "packages/sentence-structure-tree", + "packages/sentence-structure-diagram-tree" + ], "devDependencies": { - "@eslint/js": "^9.36.0", - "@types/node": "^24.6.0", - "@types/react": "^19.1.16", - "@types/react-dom": "^19.1.9", - "@vitejs/plugin-react": "^5.0.4", - "eslint": "^9.36.0", - "eslint-plugin-react-dom": "^2.2.2", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.22", - "eslint-plugin-react-x": "^2.2.2", - "globals": "^16.4.0", - "typescript": "~5.9.3", - "typescript-eslint": "^8.45.0", - "vite": "^7.1.7" + "prettier": "^3.7.4" } }, "node_modules/@babel/code-frame": { @@ -47,9 +37,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "dev": true, "license": "MIT", "engines": { @@ -57,21 +47,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -87,14 +77,21 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/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/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -180,9 +177,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -213,12 +210,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -283,17 +280,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -301,13 +298,13 @@ } }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -332,12 +329,6 @@ "stylis": "4.2.0" } }, - "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "license": "MIT" - }, "node_modules/@emotion/cache": { "version": "11.14.0", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", @@ -466,9 +457,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", - "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.1.tgz", + "integrity": "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==", "cpu": [ "ppc64" ], @@ -483,9 +474,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", - "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.1.tgz", + "integrity": "sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==", "cpu": [ "arm" ], @@ -500,9 +491,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", - "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.1.tgz", + "integrity": "sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==", "cpu": [ "arm64" ], @@ -517,9 +508,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", - "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.1.tgz", + "integrity": "sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==", "cpu": [ "x64" ], @@ -534,9 +525,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", - "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.1.tgz", + "integrity": "sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==", "cpu": [ "arm64" ], @@ -551,9 +542,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", - "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.1.tgz", + "integrity": "sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==", "cpu": [ "x64" ], @@ -568,9 +559,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", - "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.1.tgz", + "integrity": "sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==", "cpu": [ "arm64" ], @@ -585,9 +576,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", - "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.1.tgz", + "integrity": "sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==", "cpu": [ "x64" ], @@ -602,9 +593,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", - "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.1.tgz", + "integrity": "sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==", "cpu": [ "arm" ], @@ -619,9 +610,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", - "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.1.tgz", + "integrity": "sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==", "cpu": [ "arm64" ], @@ -636,9 +627,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", - "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.1.tgz", + "integrity": "sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==", "cpu": [ "ia32" ], @@ -653,9 +644,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", - "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.1.tgz", + "integrity": "sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==", "cpu": [ "loong64" ], @@ -670,9 +661,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", - "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.1.tgz", + "integrity": "sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==", "cpu": [ "mips64el" ], @@ -687,9 +678,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", - "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.1.tgz", + "integrity": "sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==", "cpu": [ "ppc64" ], @@ -704,9 +695,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", - "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.1.tgz", + "integrity": "sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==", "cpu": [ "riscv64" ], @@ -721,9 +712,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", - "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.1.tgz", + "integrity": "sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==", "cpu": [ "s390x" ], @@ -738,9 +729,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", - "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.1.tgz", + "integrity": "sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==", "cpu": [ "x64" ], @@ -755,9 +746,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", - "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.1.tgz", + "integrity": "sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==", "cpu": [ "arm64" ], @@ -772,9 +763,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", - "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.1.tgz", + "integrity": "sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==", "cpu": [ "x64" ], @@ -789,9 +780,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", - "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.1.tgz", + "integrity": "sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==", "cpu": [ "arm64" ], @@ -806,9 +797,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", - "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.1.tgz", + "integrity": "sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==", "cpu": [ "x64" ], @@ -823,9 +814,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", - "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.1.tgz", + "integrity": "sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==", "cpu": [ "arm64" ], @@ -840,9 +831,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", - "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.1.tgz", + "integrity": "sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==", "cpu": [ "x64" ], @@ -857,9 +848,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", - "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.1.tgz", + "integrity": "sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==", "cpu": [ "arm64" ], @@ -874,9 +865,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", - "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.1.tgz", + "integrity": "sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==", "cpu": [ "ia32" ], @@ -891,9 +882,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", - "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.1.tgz", + "integrity": "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==", "cpu": [ "x64" ], @@ -940,97 +931,15 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@eslint-react/ast": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@eslint-react/ast/-/ast-2.2.2.tgz", - "integrity": "sha512-Zxhfj72xEa6Lc1sxQpLETkOXDmMulR28hbWTJ2a54c0PxTKDAZ+BdOoS0KpRk8zHDc7T9q/Nq/3nvOd5Yah+nQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-react/eff": "2.2.2", - "@typescript-eslint/types": "^8.46.1", - "@typescript-eslint/typescript-estree": "^8.46.1", - "@typescript-eslint/utils": "^8.46.1", - "string-ts": "^2.2.1" - }, - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@eslint-react/core": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@eslint-react/core/-/core-2.2.2.tgz", - "integrity": "sha512-mHsSWI3/J9rROA786BJdkTodFe/WsvlN/A9laCXN/4XB+4tyaeBMfjhkCt9IffOJlfIYft2rktH8zdbAzozyGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-react/ast": "2.2.2", - "@eslint-react/eff": "2.2.2", - "@eslint-react/shared": "2.2.2", - "@eslint-react/var": "2.2.2", - "@typescript-eslint/scope-manager": "^8.46.1", - "@typescript-eslint/types": "^8.46.1", - "@typescript-eslint/utils": "^8.46.1", - "birecord": "^0.1.1", - "ts-pattern": "^5.8.0" - }, - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@eslint-react/eff": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@eslint-react/eff/-/eff-2.2.2.tgz", - "integrity": "sha512-Of0ZFSioeNs3kVuEdRKCCYJxymJ79HUiXOZq/T43zqQmfiJU6rl1JddC0sKfxEZ+nC1fX0DJDYHQbwuzoPr3DQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@eslint-react/shared": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@eslint-react/shared/-/shared-2.2.2.tgz", - "integrity": "sha512-MmSO3vUHh3SoO+Pf2qsq4s8NyBBrdE7Cm9ddFmCq8AlFhq37w2OiArkGa1qLTlizPmhpYOoDWlJi1prZVulXiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-react/eff": "2.2.2", - "@typescript-eslint/utils": "^8.46.1", - "ts-pattern": "^5.8.0", - "zod": "^4.1.12" - }, - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/@eslint-react/var": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@eslint-react/var/-/var-2.2.2.tgz", - "integrity": "sha512-psNsMfCypVaTnBDJyUFtpYb2+02mQ4lHiXN0kdnanAAXKJcDORH/1tw6k4xmv2qJ076kZtblIbhulN75RlJhmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-react/ast": "2.2.2", - "@eslint-react/eff": "2.2.2", - "@typescript-eslint/scope-manager": "^8.46.1", - "@typescript-eslint/types": "^8.46.1", - "@typescript-eslint/utils": "^8.46.1", - "ts-pattern": "^5.8.0" - }, - "engines": { - "node": ">=20.19.0" - } - }, "node_modules/@eslint/config-array": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", @@ -1047,22 +956,22 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.1.tgz", - "integrity": "sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.16.0" + "@eslint/core": "^0.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", - "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1073,9 +982,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1085,7 +994,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -1110,9 +1019,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.38.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", - "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { @@ -1133,19 +1042,40 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", - "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.16.0", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@google/genai": { + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.34.0.tgz", + "integrity": "sha512-vu53UMPvjmb7PGzlYu6Tzxso8Dfhn+a7eQFaS2uNemVtDZKwzSpJ5+ikqBbXplF7RGB1STcVDqCkPvquiwb2sw==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.24.0" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1198,6 +1128,23 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1245,9 +1192,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.4.tgz", - "integrity": "sha512-BIktMapG3r4iXwIhYNpvk97ZfYWTreBBQTWjQKbNbzI64+ULHfYavQEX2w99aSWHS58DvXESWIgbD9adKcUOBw==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.6.tgz", + "integrity": "sha512-QaYtTHlr8kDFN5mE1wbvVARRKH7Fdw1ZuOjBJcFdVpfNfRYKF3QLT4rt+WaB6CKJvpqxRsmEo0kpYinhH5GeHg==", "license": "MIT", "funding": { "type": "opencollective", @@ -1255,9 +1202,9 @@ } }, "node_modules/@mui/icons-material": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.4.tgz", - "integrity": "sha512-9n6Xcq7molXWYb680N2Qx+FRW8oT6j/LXF5PZFH3ph9X/Rct0B/BlLAsFI7iL9ySI6LVLuQIVtrLiPT82R7OZw==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.6.tgz", + "integrity": "sha512-0FfkXEj22ysIq5pa41A2NbcAhJSvmcZQ/vcTIbjDsd6hlslG82k5BEBqqS0ZJprxwIL3B45qpJ+bPHwJPlF7uQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4" @@ -1270,7 +1217,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^7.3.4", + "@mui/material": "^7.3.6", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -1281,22 +1228,22 @@ } }, "node_modules/@mui/material": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.4.tgz", - "integrity": "sha512-gEQL9pbJZZHT7lYJBKQCS723v1MGys2IFc94COXbUIyCTWa+qC77a7hUax4Yjd5ggEm35dk4AyYABpKKWC4MLw==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.6.tgz", + "integrity": "sha512-R4DaYF3dgCQCUAkr4wW1w26GHXcf5rCmBRHVBuuvJvaGLmZdD8EjatP80Nz5JCw0KxORAzwftnHzXVnjR8HnFw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/core-downloads-tracker": "^7.3.4", - "@mui/system": "^7.3.3", - "@mui/types": "^7.4.7", - "@mui/utils": "^7.3.3", + "@mui/core-downloads-tracker": "^7.3.6", + "@mui/system": "^7.3.6", + "@mui/types": "^7.4.9", + "@mui/utils": "^7.3.6", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1", - "react-is": "^19.1.1", + "react-is": "^19.2.0", "react-transition-group": "^4.4.5" }, "engines": { @@ -1309,7 +1256,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^7.3.3", + "@mui/material-pigment-css": "^7.3.6", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1330,13 +1277,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.3.tgz", - "integrity": "sha512-OJM+9nj5JIyPUvsZ5ZjaeC9PfktmK+W5YaVLToLR8L0lB/DGmv1gcKE43ssNLSvpoW71Hct0necfade6+kW3zQ==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.6.tgz", + "integrity": "sha512-Ws9wZpqM+FlnbZXaY/7yvyvWQo1+02Tbx50mVdNmzWEi51C51y56KAbaDCYyulOOBL6BJxuaqG8rNNuj7ivVyw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/utils": "^7.3.3", + "@mui/utils": "^7.3.6", "prop-types": "^15.8.1" }, "engines": { @@ -1357,9 +1304,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.3.tgz", - "integrity": "sha512-CmFxvRJIBCEaWdilhXMw/5wFJ1+FT9f3xt+m2pPXhHPeVIbBg9MnMvNSJjdALvnQJMPw8jLhrUtXmN7QAZV2fw==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.6.tgz", + "integrity": "sha512-+wiYbtvj+zyUkmDB+ysH6zRjuQIJ+CM56w0fEXV+VDNdvOuSywG+/8kpjddvvlfMLsaWdQe5oTuYGBcodmqGzQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", @@ -1391,16 +1338,16 @@ } }, "node_modules/@mui/system": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.3.tgz", - "integrity": "sha512-Lqq3emZr5IzRLKaHPuMaLBDVaGvxoh6z7HMWd1RPKawBM5uMRaQ4ImsmmgXWtwJdfZux5eugfDhXJUo2mliS8Q==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.6.tgz", + "integrity": "sha512-8fehAazkHNP1imMrdD2m2hbA9sl7Ur6jfuNweh5o4l9YPty4iaZzRXqYvBCWQNwFaSHmMEj2KPbyXGp7Bt73Rg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/private-theming": "^7.3.3", - "@mui/styled-engine": "^7.3.3", - "@mui/types": "^7.4.7", - "@mui/utils": "^7.3.3", + "@mui/private-theming": "^7.3.6", + "@mui/styled-engine": "^7.3.6", + "@mui/types": "^7.4.9", + "@mui/utils": "^7.3.6", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1431,9 +1378,9 @@ } }, "node_modules/@mui/types": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.7.tgz", - "integrity": "sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==", + "version": "7.4.9", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.9.tgz", + "integrity": "sha512-dNO8Z9T2cujkSIaCnWwprfeKmTWh97cnjkgmpFJ2sbfXLx8SMZijCYHOtP/y5nnUb/Rm2omxbDMmtUoSaUtKaw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4" @@ -1448,17 +1395,17 @@ } }, "node_modules/@mui/utils": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.3.tgz", - "integrity": "sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.6.tgz", + "integrity": "sha512-jn+Ba02O6PiFs7nKva8R2aJJ9kJC+3kQ2R0BbKNY3KQQ36Qng98GnPRFTlbwYTdMD6hLEBKaMLUktyg/rTfd2w==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/types": "^7.4.7", + "@mui/types": "^7.4.9", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^19.1.1" + "react-is": "^19.2.0" }, "engines": { "node": ">=14.0.0" @@ -1477,42 +1424,14 @@ } } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "optional": true, "engines": { - "node": ">= 8" + "node": ">=14" } }, "node_modules/@popperjs/core": { @@ -1526,16 +1445,16 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.38", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", - "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", + "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", "dev": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", - "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", + "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", "cpu": [ "arm" ], @@ -1547,9 +1466,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", - "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", + "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", "cpu": [ "arm64" ], @@ -1561,9 +1480,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", - "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", + "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", "cpu": [ "arm64" ], @@ -1575,9 +1494,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", - "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", + "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", "cpu": [ "x64" ], @@ -1589,9 +1508,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", - "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", + "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", "cpu": [ "arm64" ], @@ -1603,9 +1522,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", - "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", + "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", "cpu": [ "x64" ], @@ -1617,9 +1536,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", - "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", + "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", "cpu": [ "arm" ], @@ -1631,9 +1550,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", - "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", + "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", "cpu": [ "arm" ], @@ -1645,9 +1564,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", - "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", + "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", "cpu": [ "arm64" ], @@ -1659,9 +1578,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", - "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", + "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", "cpu": [ "arm64" ], @@ -1673,9 +1592,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", - "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", + "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", "cpu": [ "loong64" ], @@ -1687,9 +1606,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", - "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", + "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", "cpu": [ "ppc64" ], @@ -1701,9 +1620,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", - "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", + "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", "cpu": [ "riscv64" ], @@ -1715,9 +1634,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", - "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", + "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", "cpu": [ "riscv64" ], @@ -1729,9 +1648,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", - "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", + "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", "cpu": [ "s390x" ], @@ -1743,9 +1662,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", - "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", + "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", "cpu": [ "x64" ], @@ -1757,9 +1676,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", - "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", + "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", "cpu": [ "x64" ], @@ -1771,9 +1690,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", - "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", + "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", "cpu": [ "arm64" ], @@ -1785,9 +1704,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", - "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", + "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", "cpu": [ "arm64" ], @@ -1799,9 +1718,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", - "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", + "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", "cpu": [ "ia32" ], @@ -1813,9 +1732,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", - "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", + "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", "cpu": [ "x64" ], @@ -1827,9 +1746,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", - "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", + "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", "cpu": [ "x64" ], @@ -1840,6 +1759,110 @@ "win32" ] }, + "node_modules/@sentence-structure-diagram-app/backend": { + "resolved": "packages/backend", + "link": true + }, + "node_modules/@sentence-structure-diagram-app/evaluation": { + "resolved": "packages/evaluation", + "link": true + }, + "node_modules/@sentence-structure-diagram-app/frontend": { + "resolved": "packages/frontend", + "link": true + }, + "node_modules/@sentence-structure-diagram-app/sentence-structure-data": { + "resolved": "packages/sentence-structure-data", + "link": true + }, + "node_modules/@sentence-structure-diagram-app/sentence-structure-diagram-configurations": { + "resolved": "packages/sentence-structure-diagram-configurations", + "link": true + }, + "node_modules/@sentence-structure-diagram-app/sentence-structure-diagram-data": { + "resolved": "packages/sentence-structure-diagram-data", + "link": true + }, + "node_modules/@sentence-structure-diagram-app/sentence-structure-diagram-svg": { + "resolved": "packages/sentence-structure-diagram-svg", + "link": true + }, + "node_modules/@sentence-structure-diagram-app/sentence-structure-diagram-tree": { + "resolved": "packages/sentence-structure-diagram-tree", + "link": true + }, + "node_modules/@sentence-structure-diagram-app/sentence-structure-tree": { + "resolved": "packages/sentence-structure-tree", + "link": true + }, + "node_modules/@tanstack/query-core": { + "version": "5.90.12", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.12.tgz", + "integrity": "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.12.tgz", + "integrity": "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@trpc/client": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@trpc/client/-/client-11.7.2.tgz", + "integrity": "sha512-OQxqUMfpDvjcszo9dbnqWQXnW2L5IbrKSz2H7l8s+mVM3EvYw7ztQ/gjFIN3iy0NcamiQfd4eE6qjcb9Lm+63A==", + "funding": [ + "https://trpc.io/sponsor" + ], + "license": "MIT", + "peerDependencies": { + "@trpc/server": "11.7.2", + "typescript": ">=5.7.2" + } + }, + "node_modules/@trpc/server": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@trpc/server/-/server-11.7.2.tgz", + "integrity": "sha512-AgB26PXY69sckherIhCacKLY49rxE2XP5h38vr/KMZTbLCL1p8IuIoKPjALTcugC2kbyQ7Lbqo2JDVfRSmPmfQ==", + "funding": [ + "https://trpc.io/sponsor" + ], + "license": "MIT", + "peerDependencies": { + "typescript": ">=5.7.2" + } + }, + "node_modules/@trpc/tanstack-react-query": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@trpc/tanstack-react-query/-/tanstack-react-query-11.7.2.tgz", + "integrity": "sha512-3XrY0b8lV0Fhj4Z2hVn1d1ZJzq2/stbc2F1e9Y6RrUWOfLmOKHlEVHYO1QfDGM6rqj66DkUj7eA593hAI0VTkQ==", + "funding": [ + "https://trpc.io/sponsor" + ], + "license": "MIT", + "peerDependencies": { + "@tanstack/react-query": "^5.80.3", + "@trpc/client": "11.7.2", + "@trpc/server": "11.7.2", + "react": ">=18.2.0", + "react-dom": ">=18.2.0", + "typescript": ">=5.7.2" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1885,6 +1908,37 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1892,6 +1946,38 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", + "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1900,13 +1986,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.8.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.8.1.tgz", - "integrity": "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==", + "version": "24.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz", + "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.14.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/parse-json": { @@ -1921,19 +2007,33 @@ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "license": "MIT" }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", "dependencies": { - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", - "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1949,19 +2049,39 @@ "@types/react": "*" } }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz", - "integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.49.0.tgz", + "integrity": "sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/type-utils": "8.46.1", - "@typescript-eslint/utils": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", - "graphemer": "^1.4.0", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/type-utils": "8.49.0", + "@typescript-eslint/utils": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" @@ -1974,7 +2094,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.46.1", + "@typescript-eslint/parser": "^8.49.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -1990,16 +2110,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.1.tgz", - "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.49.0.tgz", + "integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", "debug": "^4.3.4" }, "engines": { @@ -2015,14 +2135,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.1.tgz", - "integrity": "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.49.0.tgz", + "integrity": "sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.1", - "@typescript-eslint/types": "^8.46.1", + "@typescript-eslint/tsconfig-utils": "^8.49.0", + "@typescript-eslint/types": "^8.49.0", "debug": "^4.3.4" }, "engines": { @@ -2037,14 +2157,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.1.tgz", - "integrity": "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.49.0.tgz", + "integrity": "sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1" + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2055,9 +2175,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.1.tgz", - "integrity": "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.49.0.tgz", + "integrity": "sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==", "dev": true, "license": "MIT", "engines": { @@ -2072,15 +2192,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.1.tgz", - "integrity": "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.49.0.tgz", + "integrity": "sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1", - "@typescript-eslint/utils": "8.46.1", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/utils": "8.49.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -2097,9 +2217,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.1.tgz", - "integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.49.0.tgz", + "integrity": "sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==", "dev": true, "license": "MIT", "engines": { @@ -2111,21 +2231,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.1.tgz", - "integrity": "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.49.0.tgz", + "integrity": "sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.46.1", - "@typescript-eslint/tsconfig-utils": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", + "@typescript-eslint/project-service": "8.49.0", + "@typescript-eslint/tsconfig-utils": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", + "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "engines": { @@ -2179,16 +2298,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.1.tgz", - "integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.49.0.tgz", + "integrity": "sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1" + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2203,13 +2322,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.1.tgz", - "integrity": "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.49.0.tgz", + "integrity": "sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/types": "8.49.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -2221,18 +2340,18 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", - "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz", + "integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.4", + "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.38", + "@rolldown/pluginutils": "1.0.0-beta.53", "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "react-refresh": "^0.18.0" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -2241,6 +2360,19 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2264,6 +2396,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2281,11 +2422,22 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -2323,25 +2475,70 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.18", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.18.tgz", - "integrity": "sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.6.tgz", + "integrity": "sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg==", "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" } }, - "node_modules/birecord": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/birecord/-/birecord-0.1.1.tgz", - "integrity": "sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==", - "dev": true, - "license": "(MIT OR Apache-2.0)" + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/body-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, "node_modules/brace-expansion": { "version": "1.1.12", @@ -2354,23 +2551,10 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/browserslist": { - "version": "4.26.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", - "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -2388,11 +2572,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.9", - "caniuse-lite": "^1.0.30001746", - "electron-to-chromium": "^1.5.227", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -2401,9 +2585,53 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.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==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "license": "MIT", "engines": { @@ -2411,9 +2639,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001751", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", - "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "version": "1.0.30001760", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", + "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", "dev": true, "funding": [ { @@ -2461,7 +2689,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -2474,15 +2701,21 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, - "node_modules/compare-versions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", - "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", - "dev": true, - "license": "MIT" + "node_modules/compromise": { + "version": "14.14.4", + "resolved": "https://registry.npmjs.org/compromise/-/compromise-14.14.4.tgz", + "integrity": "sha512-QdbJwronwxeqb7a5KFK/+Y5YieZ4PE1f7ai0vU58Pp4jih+soDCBMuKVbhDEPQ+6+vI3vSiG4UAAjTAXLJw1Qw==", + "license": "MIT", + "dependencies": { + "efrt": "2.7.0", + "grad-school": "0.0.5", + "suffix-thumb": "5.0.2" + }, + "engines": { + "node": ">=12.0.0" + } }, "node_modules/concat-map": { "version": "0.0.1", @@ -2491,13 +2724,65 @@ "dev": true, "license": "MIT" }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "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, + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "license": "MIT" }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -2527,7 +2812,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -2539,11 +2823,20 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "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/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -2568,6 +2861,15 @@ "dev": true, "license": "MIT" }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -2578,13 +2880,72 @@ "csstype": "^3.0.2" } }, + "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==", + "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/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/efrt": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/efrt/-/efrt-2.7.0.tgz", + "integrity": "sha512-/RInbCy1d4P6Zdfa+TMVsf/ufZVotat5hCw3QXmWtjU+3pFEOvOQ7ibo3aIxyCJw2leIeAMjmPj+1SLJiCpdrQ==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/electron-to-chromium": { - "version": "1.5.237", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", - "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", "dev": true, "license": "ISC" }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -2594,10 +2955,40 @@ "is-arrayish": "^0.2.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==", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", - "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.1.tgz", + "integrity": "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2608,32 +2999,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.11", - "@esbuild/android-arm": "0.25.11", - "@esbuild/android-arm64": "0.25.11", - "@esbuild/android-x64": "0.25.11", - "@esbuild/darwin-arm64": "0.25.11", - "@esbuild/darwin-x64": "0.25.11", - "@esbuild/freebsd-arm64": "0.25.11", - "@esbuild/freebsd-x64": "0.25.11", - "@esbuild/linux-arm": "0.25.11", - "@esbuild/linux-arm64": "0.25.11", - "@esbuild/linux-ia32": "0.25.11", - "@esbuild/linux-loong64": "0.25.11", - "@esbuild/linux-mips64el": "0.25.11", - "@esbuild/linux-ppc64": "0.25.11", - "@esbuild/linux-riscv64": "0.25.11", - "@esbuild/linux-s390x": "0.25.11", - "@esbuild/linux-x64": "0.25.11", - "@esbuild/netbsd-arm64": "0.25.11", - "@esbuild/netbsd-x64": "0.25.11", - "@esbuild/openbsd-arm64": "0.25.11", - "@esbuild/openbsd-x64": "0.25.11", - "@esbuild/openharmony-arm64": "0.25.11", - "@esbuild/sunos-x64": "0.25.11", - "@esbuild/win32-arm64": "0.25.11", - "@esbuild/win32-ia32": "0.25.11", - "@esbuild/win32-x64": "0.25.11" + "@esbuild/aix-ppc64": "0.27.1", + "@esbuild/android-arm": "0.27.1", + "@esbuild/android-arm64": "0.27.1", + "@esbuild/android-x64": "0.27.1", + "@esbuild/darwin-arm64": "0.27.1", + "@esbuild/darwin-x64": "0.27.1", + "@esbuild/freebsd-arm64": "0.27.1", + "@esbuild/freebsd-x64": "0.27.1", + "@esbuild/linux-arm": "0.27.1", + "@esbuild/linux-arm64": "0.27.1", + "@esbuild/linux-ia32": "0.27.1", + "@esbuild/linux-loong64": "0.27.1", + "@esbuild/linux-mips64el": "0.27.1", + "@esbuild/linux-ppc64": "0.27.1", + "@esbuild/linux-riscv64": "0.27.1", + "@esbuild/linux-s390x": "0.27.1", + "@esbuild/linux-x64": "0.27.1", + "@esbuild/netbsd-arm64": "0.27.1", + "@esbuild/netbsd-x64": "0.27.1", + "@esbuild/openbsd-arm64": "0.27.1", + "@esbuild/openbsd-x64": "0.27.1", + "@esbuild/openharmony-arm64": "0.27.1", + "@esbuild/sunos-x64": "0.27.1", + "@esbuild/win32-arm64": "0.27.1", + "@esbuild/win32-ia32": "0.27.1", + "@esbuild/win32-x64": "0.27.1" } }, "node_modules/escalade": { @@ -2646,6 +3037,12 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2659,20 +3056,20 @@ } }, "node_modules/eslint": { - "version": "9.38.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", - "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.1", - "@eslint/core": "^0.16.0", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.38.0", - "@eslint/plugin-kit": "^0.4.0", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -2718,41 +3115,21 @@ } } }, - "node_modules/eslint-plugin-react-dom": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-dom/-/eslint-plugin-react-dom-2.2.2.tgz", - "integrity": "sha512-0M46zRkB6b4RFLOVYMwrKP/bN0fHTTt+En4k/oDel4iu3cFJtRuEy8+YjtFcf2ab+BS7MJzF1kL0Ye7oA6WcEA==", + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-react/ast": "2.2.2", - "@eslint-react/core": "2.2.2", - "@eslint-react/eff": "2.2.2", - "@eslint-react/shared": "2.2.2", - "@eslint-react/var": "2.2.2", - "@typescript-eslint/scope-manager": "^8.46.1", - "@typescript-eslint/types": "^8.46.1", - "@typescript-eslint/utils": "^8.46.1", - "compare-versions": "^6.1.1", - "string-ts": "^2.2.1", - "ts-pattern": "^5.8.0" + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" }, "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "eslint": "^9.37.0", - "typescript": "^5.9.3" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" @@ -2768,36 +3145,6 @@ "eslint": ">=8.40" } }, - "node_modules/eslint-plugin-react-x": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-x/-/eslint-plugin-react-x-2.2.2.tgz", - "integrity": "sha512-YfRSuVttlZoXju1cM/ks8Sp5q7e5izEZXBpPdTnOVEyBu+ioNGwu0b3dfSJ+WYcNHjNdpQD2WHbHcUNlR9qQzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-react/ast": "2.2.2", - "@eslint-react/core": "2.2.2", - "@eslint-react/eff": "2.2.2", - "@eslint-react/shared": "2.2.2", - "@eslint-react/var": "2.2.2", - "@typescript-eslint/scope-manager": "^8.46.1", - "@typescript-eslint/type-utils": "^8.46.1", - "@typescript-eslint/types": "^8.46.1", - "@typescript-eslint/utils": "^8.46.1", - "compare-versions": "^6.1.1", - "is-immutable-type": "^5.0.1", - "string-ts": "^2.2.1", - "ts-api-utils": "^2.1.0", - "ts-pattern": "^5.8.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "eslint": "^9.37.0", - "typescript": "^5.9.3" - } - }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -2892,43 +3239,71 @@ "node": ">=0.10.0" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, "engines": { - "node": ">=8.6.0" + "node": ">= 0.6" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" }, - "engines": { - "node": ">= 6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, + "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/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2943,14 +3318,63 @@ "dev": true, "license": "MIT" }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "node_modules/fast-xml-parser": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.3.tgz", + "integrity": "sha512-2O3dkPAAC6JavuMm8+4+pgTk+5hoAs+CjZ+sWcQLkX9+/tHRuTkQh/Oaifr8qDmZ8iEHb771Ea6G8CdwkrgvYA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, - "license": "ISC", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", "dependencies": { - "reusify": "^1.0.4" + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" } }, "node_modules/file-entry-cache": { @@ -2966,17 +3390,25 @@ "node": ">=16.0.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/find-root": { @@ -3023,30 +3455,105 @@ "dev": true, "license": "ISC" }, - "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" - ], + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "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==", + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gaxios": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz", + "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2", + "rimraf": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3057,6 +3564,76 @@ "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==", + "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==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3070,10 +3647,34 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "license": "MIT", "engines": { @@ -3083,12 +3684,66 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" + "node_modules/google-auth-library": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz", + "integrity": "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.0.0", + "gcp-metadata": "^8.0.0", + "google-logging-utils": "^1.0.0", + "gtoken": "^8.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/grad-school": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/grad-school/-/grad-school-0.0.5.tgz", + "integrity": "sha512-rXunEHF9M9EkMydTBux7+IryYXEZinRk6g8OBOGDBzo/qWJjhTxy86i5q7lQYpCLHN8Sqv1XX3OIOc7ka2gtvQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/gtoken": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", + "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", + "license": "MIT", + "dependencies": { + "gaxios": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } }, "node_modules/has-flag": { "version": "4.0.0", @@ -3100,6 +3755,18 @@ "node": ">=8" } }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -3112,6 +3779,23 @@ "node": ">= 0.4" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -3127,6 +3811,55 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3163,6 +3896,21 @@ "node": ">=0.8.19" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3194,6 +3942,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3207,39 +3964,33 @@ "node": ">=0.10.0" } }, - "node_modules/is-immutable-type": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/is-immutable-type/-/is-immutable-type-5.0.1.tgz", - "integrity": "sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@typescript-eslint/type-utils": "^8.0.0", - "ts-api-utils": "^2.0.0", - "ts-declaration-location": "^1.0.4" - }, - "peerDependencies": { - "eslint": "*", - "typescript": ">=4.7.4" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3247,9 +3998,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -3271,6 +4022,15 @@ "node": ">=6" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -3311,6 +4071,27 @@ "node": ">=6" } }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -3386,43 +4167,83 @@ "yallist": "^3.0.2" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, + "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==", "license": "MIT", "engines": { - "node": ">= 8" + "node": ">= 0.4" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, "engines": { - "node": ">=8.6" + "node": ">= 0.8" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { "node": "*" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3455,10 +4276,57 @@ "dev": true, "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/node-releases": { - "version": "2.0.25", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz", - "integrity": "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, "license": "MIT" }, @@ -3471,6 +4339,60 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openai": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.15.0.tgz", + "integrity": "sha512-F1Lvs5BoVvmZtzkUEVyh8mDQPPFolq4F+xdsx/DO8Hee8YF3IGAlZqUIsF+DVGhqf4aU0a3bTghsxB6OIsRy1g==", + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -3521,6 +4443,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3551,6 +4479,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3565,7 +4502,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3577,6 +4513,38 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/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==", + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3593,13 +4561,13 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -3644,6 +4612,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -3661,6 +4644,19 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3671,58 +4667,76 @@ "node": ">=6" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } }, "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.0" + "react": "^19.2.3" } }, "node_modules/react-is": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", - "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.1.tgz", + "integrity": "sha512-L7BnWgRbMwzMAubQcS7sXdPdNLmKlucPlopgAzx7FtYbksWZgEWiuYM5x9T6UqS2Ne0rsgQTq5kY2SGqpzUkYA==", "license": "MIT" }, "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "dev": true, "license": "MIT", "engines": { @@ -3746,12 +4760,12 @@ } }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -3774,21 +4788,35 @@ "node": ">=4" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rollup": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", - "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", + "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, "license": "MIT", "dependencies": { @@ -3802,36 +4830,51 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.5", - "@rollup/rollup-android-arm64": "4.52.5", - "@rollup/rollup-darwin-arm64": "4.52.5", - "@rollup/rollup-darwin-x64": "4.52.5", - "@rollup/rollup-freebsd-arm64": "4.52.5", - "@rollup/rollup-freebsd-x64": "4.52.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", - "@rollup/rollup-linux-arm-musleabihf": "4.52.5", - "@rollup/rollup-linux-arm64-gnu": "4.52.5", - "@rollup/rollup-linux-arm64-musl": "4.52.5", - "@rollup/rollup-linux-loong64-gnu": "4.52.5", - "@rollup/rollup-linux-ppc64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-musl": "4.52.5", - "@rollup/rollup-linux-s390x-gnu": "4.52.5", - "@rollup/rollup-linux-x64-gnu": "4.52.5", - "@rollup/rollup-linux-x64-musl": "4.52.5", - "@rollup/rollup-openharmony-arm64": "4.52.5", - "@rollup/rollup-win32-arm64-msvc": "4.52.5", - "@rollup/rollup-win32-ia32-msvc": "4.52.5", - "@rollup/rollup-win32-x64-gnu": "4.52.5", - "@rollup/rollup-win32-x64-msvc": "4.52.5", + "@rollup/rollup-android-arm-eabi": "4.53.3", + "@rollup/rollup-android-arm64": "4.53.3", + "@rollup/rollup-darwin-arm64": "4.53.3", + "@rollup/rollup-darwin-x64": "4.53.3", + "@rollup/rollup-freebsd-arm64": "4.53.3", + "@rollup/rollup-freebsd-x64": "4.53.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", + "@rollup/rollup-linux-arm64-gnu": "4.53.3", + "@rollup/rollup-linux-arm64-musl": "4.53.3", + "@rollup/rollup-linux-loong64-gnu": "4.53.3", + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-musl": "4.53.3", + "@rollup/rollup-linux-s390x-gnu": "4.53.3", + "@rollup/rollup-linux-x64-gnu": "4.53.3", + "@rollup/rollup-linux-x64-musl": "4.53.3", + "@rollup/rollup-openharmony-arm64": "4.53.3", + "@rollup/rollup-win32-arm64-msvc": "4.53.3", + "@rollup/rollup-win32-ia32-msvc": "4.53.3", + "@rollup/rollup-win32-x64-gnu": "4.53.3", + "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -3846,10 +4889,13 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } + "license": "MIT" + }, + "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/scheduler": { "version": "0.27.0", @@ -3867,11 +4913,53 @@ "semver": "bin/semver.js" } }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -3884,39 +4972,220 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string-ts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/string-ts/-/string-ts-2.2.1.tgz", - "integrity": "sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==", - "dev": true, - "license": "MIT" - }, - "node_modules/strip-json-comments": { + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", @@ -3929,12 +5198,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", "license": "MIT" }, + "node_modules/suffix-thumb": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/suffix-thumb/-/suffix-thumb-5.0.2.tgz", + "integrity": "sha512-I5PWXAFKx3FYnI9a+dQMWNqTxoRt6vdBdb0O+BJ1sxXCWtSoQCusc13E58f+9p4MYx/qCnEMkD5jac6K2j3dgA==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3977,48 +5264,13 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, "engines": { - "node": ">=8.0" + "node": ">=0.6" } }, "node_modules/ts-api-utils": { @@ -4034,49 +5286,26 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-declaration-location": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", - "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, - "funding": [ - { - "type": "ko-fi", - "url": "https://ko-fi.com/rebeccastevens" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" - } - ], - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "picomatch": "^4.0.2" + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" }, - "peerDependencies": { - "typescript": ">=4.0.0" - } - }, - "node_modules/ts-declaration-location/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "optionalDependencies": { + "fsevents": "~2.3.3" } }, - "node_modules/ts-pattern": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.8.0.tgz", - "integrity": "sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==", - "dev": true, - "license": "MIT" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4090,11 +5319,24 @@ "node": ">= 0.8.0" } }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -4105,16 +5347,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.1.tgz", - "integrity": "sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.49.0.tgz", + "integrity": "sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.46.1", - "@typescript-eslint/parser": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1", - "@typescript-eslint/utils": "8.46.1" + "@typescript-eslint/eslint-plugin": "8.49.0", + "@typescript-eslint/parser": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/utils": "8.49.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4129,16 +5371,25 @@ } }, "node_modules/undici-types": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", - "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", + "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", "dev": true, "funding": [ { @@ -4176,10 +5427,19 @@ "punycode": "^2.1.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vite": { - "version": "7.1.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", - "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", + "version": "7.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.7.tgz", + "integrity": "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4251,49 +5511,510 @@ } } }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "node": ">=18" } }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">=18" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, "engines": { "node": ">= 8" } @@ -4308,6 +6029,121 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "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/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -4315,21 +6151,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -4344,14 +6165,171 @@ } }, "node_modules/zod": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", - "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", - "dev": true, + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz", + "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "packages/backend": { + "name": "@sentence-structure-diagram-app/backend", + "version": "0.1.0", + "dependencies": { + "@google/genai": "^1.33.0", + "@sentence-structure-diagram-app/evaluation": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@trpc/server": "^11.7.2", + "cors": "^2.8.5", + "express": "^5.2.1", + "zod": "^4.1.13" + }, + "devDependencies": { + "@types/cors": "^2.8.19", + "@types/express": "^5.0.6", + "@types/node": "^24.10.3", + "tsx": "^4.21.0", + "typescript": "^5.9.3" + } + }, + "packages/evaluation": { + "name": "@sentence-structure-diagram-app/evaluation", + "version": "0.1.0", + "dependencies": { + "@google/genai": "^1.34.0", + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-configurations": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-svg": "^0.1.0", + "openai": "^6.15.0", + "zod": "^4.2.1" + }, + "devDependencies": { + "@types/node": "^24.10.4", + "tsx": "^4.21.0", + "typescript": "^5.9.3" + } + }, + "packages/frontend": { + "name": "@sentence-structure-diagram-app/frontend", + "version": "0.1.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/icons-material": "^7.3.6", + "@mui/material": "^7.3.6", + "@sentence-structure-diagram-app/backend": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-svg": "^0.1.0", + "@tanstack/react-query": "^5.90.12", + "@trpc/client": "^11.7.2", + "@trpc/tanstack-react-query": "^11.7.2", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/node": "^24.10.1", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "^7.2.4" + } + }, + "packages/sentence-structure-data": { + "name": "@sentence-structure-diagram-app/sentence-structure-data", + "version": "0.1.0", + "dependencies": { + "compromise": "^14.14.4", + "fast-xml-parser": "^5.3.2", + "zod": "^4.1.13" + }, + "devDependencies": { + "typescript": "^5.9.3" + } + }, + "packages/sentence-structure-diagram-configurations": { + "name": "@sentence-structure-diagram-app/sentence-structure-diagram-configurations", + "version": "0.1.0", + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "fast-xml-parser": "^5.3.3", + "zod": "^4.2.1" + }, + "devDependencies": { + "typescript": "^5.9.3" + } + }, + "packages/sentence-structure-diagram-data": { + "name": "@sentence-structure-diagram-app/sentence-structure-diagram-data", + "version": "0.1.0", + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-configurations": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-tree": "^0.1.0", + "fast-xml-parser": "^5.3.2", + "zod": "^4.1.13" + }, + "devDependencies": { + "typescript": "^5.9.3" + } + }, + "packages/sentence-structure-diagram-svg": { + "name": "@sentence-structure-diagram-app/sentence-structure-diagram-svg", + "version": "0.1.0", + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-configurations": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-data": "^0.1.0", + "prettier": "^3.7.4", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "typescript": "^5.9.3" + } + }, + "packages/sentence-structure-diagram-tree": { + "name": "@sentence-structure-diagram-app/sentence-structure-diagram-tree", + "version": "0.1.0", + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-configurations": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-tree": "^0.1.0" + }, + "devDependencies": { + "typescript": "^5.9.3" + } + }, + "packages/sentence-structure-tree": { + "name": "@sentence-structure-diagram-app/sentence-structure-tree", + "version": "0.1.0", + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0" + }, + "devDependencies": { + "typescript": "^5.9.3" + } } } } diff --git a/package.json b/package.json index 64b6982..70c57cc 100644 --- a/package.json +++ b/package.json @@ -1,36 +1,26 @@ { "name": "sentence-structure-diagram-app", - "private": true, - "version": "0.0.0", + "version": "0.1.0", "type": "module", "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.1", - "@mui/icons-material": "^7.3.4", - "@mui/material": "^7.3.4", - "react": "^19.1.1", - "react-dom": "^19.1.1" + "build:packages": "npm run build --workspace=packages/sentence-structure-data && npm run build --workspace=packages/sentence-structure-tree && npm run build --workspace=packages/sentence-structure-diagram-configurations && npm run build --workspace=packages/sentence-structure-diagram-tree && npm run build --workspace=packages/sentence-structure-diagram-data && npm run build --workspace=packages/sentence-structure-diagram-svg", + "build": "npm run build:packages && npm run build --workspace=packages/evaluation && npm run build --workspace=packages/backend && npm run build --workspace=packages/frontend", + "format": "prettier --write .", + "format:check": "prettier --check .", + "clean": "npm run clean --workspaces" }, "devDependencies": { - "@eslint/js": "^9.36.0", - "@types/node": "^24.6.0", - "@types/react": "^19.1.16", - "@types/react-dom": "^19.1.9", - "@vitejs/plugin-react": "^5.0.4", - "eslint": "^9.36.0", - "eslint-plugin-react-dom": "^2.2.2", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.22", - "eslint-plugin-react-x": "^2.2.2", - "globals": "^16.4.0", - "typescript": "~5.9.3", - "typescript-eslint": "^8.45.0", - "vite": "^7.1.7" - } + "prettier": "^3.7.4" + }, + "workspaces": [ + "packages/backend", + "packages/frontend", + "packages/sentence-structure-data", + "packages/sentence-structure-diagram-data", + "packages/sentence-structure-diagram-svg", + "packages/evaluation", + "packages/sentence-structure-diagram-configurations", + "packages/sentence-structure-tree", + "packages/sentence-structure-diagram-tree" + ] } diff --git a/packages/backend/.env.sample b/packages/backend/.env.sample new file mode 100644 index 0000000..623d822 --- /dev/null +++ b/packages/backend/.env.sample @@ -0,0 +1,3 @@ +WEB_ORIGIN=http://localhost:5173 + +GEMINI_API_KEY= diff --git a/packages/backend/.gitignore b/packages/backend/.gitignore new file mode 100644 index 0000000..22a1e06 --- /dev/null +++ b/packages/backend/.gitignore @@ -0,0 +1,2 @@ +/dist +/.env diff --git a/packages/backend/_app.ts b/packages/backend/_app.ts new file mode 100644 index 0000000..593da96 --- /dev/null +++ b/packages/backend/_app.ts @@ -0,0 +1,25 @@ +import { publicProcedure, router } from "./trpc.js"; +import * as z from "zod"; +import { SimplifiedAnnotationDataSchema } from "@sentence-structure-diagram-app/sentence-structure-data"; +import { generateSimplifiedAnnotationDataByGemini } from "./generate-simplified-annotation-by-gemini.js"; + +export const appRouter = router({ + status: publicProcedure + .output(z.object({ status: z.literal("ok") })) + .query(() => ({ status: "ok" })), + generateSentenceStructure: publicProcedure + .input( + z.object({ + text: z.string(), + words: z.array(z.string()), + }), + ) + .output(SimplifiedAnnotationDataSchema) + .mutation(async (opts) => { + const text = opts.input.text; + const words = opts.input.words; + console.log(`Input text: ${text}`); + + return await generateSimplifiedAnnotationDataByGemini(text, words); + }), +}); diff --git a/packages/backend/generate-simplified-annotation-by-gemini.ts b/packages/backend/generate-simplified-annotation-by-gemini.ts new file mode 100644 index 0000000..5a506dc --- /dev/null +++ b/packages/backend/generate-simplified-annotation-by-gemini.ts @@ -0,0 +1,43 @@ +import { GoogleGenAI } from "@google/genai"; +import { + SimplifiedAnnotationDataSchema, + type SimplifiedAnnotationData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import { generateGeminiPrompt } from "@sentence-structure-diagram-app/evaluation"; + +const ai = new GoogleGenAI({}); + +export async function generateSimplifiedAnnotationDataByGemini( + text: string, + words: string[], +): Promise { + const prompt = generateGeminiPrompt(text, words); + try { + const result = await ai.models.generateContent({ + model: "gemini-2.5-flash", + contents: prompt.userInput, + config: { + systemInstruction: prompt.systemInstruction, + responseMimeType: "application/json", + // responseJsonSchema: z.toJSONSchema(SimplifiedAnnotationDataSchema), + }, + }); + if (!result.text) throw new Error("AI returned no result"); + const json = (() => { + try { + return JSON.parse(result.text); + } catch { + throw new Error("AI returned invalid JSON"); + } + })(); + console.log("Generated JSON:", JSON.stringify(json, null, 2)); + try { + return SimplifiedAnnotationDataSchema.parse(json); + } catch { + throw new Error("AI returned JSON with invalid schema"); + } + } catch (error) { + console.error(error); + throw error; + } +} diff --git a/packages/backend/index.ts b/packages/backend/index.ts new file mode 100644 index 0000000..710c71f --- /dev/null +++ b/packages/backend/index.ts @@ -0,0 +1,22 @@ +import express from "express"; +import cors from "cors"; +import * as trpcExpress from "@trpc/server/adapters/express"; +import { createContext } from "./trpc.js"; +import { appRouter } from "./_app.js"; + +export type AppRouter = typeof appRouter; + +const app = express(); + +app.use( + "/trpc", + trpcExpress.createExpressMiddleware({ + middleware: cors({ origin: process.env.WEB_ORIGIN }), + router: appRouter, + createContext, + }), +); + +app.listen(3000, () => { + console.log("Server is running on port 3000"); +}); diff --git a/packages/backend/package.json b/packages/backend/package.json new file mode 100644 index 0000000..d3df95f --- /dev/null +++ b/packages/backend/package.json @@ -0,0 +1,28 @@ +{ + "name": "@sentence-structure-diagram-app/backend", + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "scripts": { + "dev": "tsx watch --env-file=.env index.ts", + "build": "tsc", + "start": "node dist/index.js", + "clean": "rm -r dist" + }, + "dependencies": { + "@google/genai": "^1.33.0", + "@sentence-structure-diagram-app/evaluation": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@trpc/server": "^11.7.2", + "cors": "^2.8.5", + "express": "^5.2.1", + "zod": "^4.1.13" + }, + "devDependencies": { + "@types/cors": "^2.8.19", + "@types/express": "^5.0.6", + "@types/node": "^24.10.3", + "tsx": "^4.21.0", + "typescript": "^5.9.3" + } +} diff --git a/packages/backend/trpc.ts b/packages/backend/trpc.ts new file mode 100644 index 0000000..6ac8e24 --- /dev/null +++ b/packages/backend/trpc.ts @@ -0,0 +1,13 @@ +import { initTRPC } from "@trpc/server"; +import * as trpcExpress from "@trpc/server/adapters/express"; + +export const createContext = ({ + req, + res, +}: trpcExpress.CreateExpressContextOptions) => ({}); +type Context = Awaited>; + +const t = initTRPC.context().create(); + +export const router = t.router; +export const publicProcedure = t.procedure; diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json new file mode 100644 index 0000000..d6a2b39 --- /dev/null +++ b/packages/backend/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/packages/evaluation/.env.sample b/packages/evaluation/.env.sample new file mode 100644 index 0000000..e70c68d --- /dev/null +++ b/packages/evaluation/.env.sample @@ -0,0 +1,9 @@ +GEMINI_API_KEY= + +AZURE_OPENAI_ENDPOINT= +AZURE_OPENAI_API_KEY= +AZURE_OPENAI_API_VERSION= +AZURE_OPENAI_GPT5_DEPLOYMENT_NAME= +AZURE_OPENAI_GPT5_1_DEPLOYMENT_NAME= +AZURE_OPENAI_GPT5_2_DEPLOYMENT_NAME= +AZURE_OPENAI_LLAMA4_DEPLOYMENT_NAME= diff --git a/packages/evaluation/.gitignore b/packages/evaluation/.gitignore new file mode 100644 index 0000000..86d3f12 --- /dev/null +++ b/packages/evaluation/.gitignore @@ -0,0 +1,4 @@ +/dist +/.env +/data +/output diff --git a/packages/evaluation/calculate-metrics.ts b/packages/evaluation/calculate-metrics.ts new file mode 100644 index 0000000..ff35a7a --- /dev/null +++ b/packages/evaluation/calculate-metrics.ts @@ -0,0 +1,286 @@ +import { + findRangeById, + type Range, + type SentenceStructureData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; + +function isSameRange(range1: Range, range2: Range): boolean { + return ( + range1.startWordIndex === range2.startWordIndex && + range1.endWordIndex === range2.endWordIndex && + range1.type === range2.type && + (range1.type === "relation" || + (range2.type !== "relation" && + range1.sentenceElementName === range2.sentenceElementName)) + ); +} + +function isSameRangeStartAndEndWordIndex( + range1: Range, + range2: Range, +): boolean { + return ( + range1.startWordIndex === range2.startWordIndex && + range1.endWordIndex === range2.endWordIndex + ); +} + +type CompareResult = { + answerRangeCount: number; + answerRelationCount: number; + answerCoordinationCount: number; + llmAnswerRangeCount: number; + llmAnswerRelationCount: number; + llmAnswerCoordinationCount: number; + correctRangeCount: number; + correctRangeStartAndEndWordIndexCount: number; + correctRelationCount: number; + correctRelationStartAndEndWordIndexCount: number; + correctCoordinationCount: number; + correctCoordinationStartAndEndWordIndexCount: number; +}; + +function compareSentenceStructureData( + answer: SentenceStructureData, + llmAnswer: SentenceStructureData | null, +): CompareResult { + return { + answerRangeCount: answer.ranges.length, + answerRelationCount: answer.relations.length, + answerCoordinationCount: answer.coordinations.length, + llmAnswerRangeCount: llmAnswer?.ranges.length ?? 0, + llmAnswerRelationCount: llmAnswer?.relations.length ?? 0, + llmAnswerCoordinationCount: llmAnswer?.coordinations.length ?? 0, + correctRangeCount: + llmAnswer?.ranges.filter((llmRange) => + answer.ranges.some((answerRange) => isSameRange(llmRange, answerRange)), + ).length ?? 0, + correctRangeStartAndEndWordIndexCount: + llmAnswer?.ranges.filter((llmRange) => + answer.ranges.some((answerRange) => + isSameRangeStartAndEndWordIndex(llmRange, answerRange), + ), + ).length ?? 0, + correctRelationCount: + llmAnswer?.relations.filter((llmRelation) => + answer.relations.some( + (answerRelation) => + isSameRange( + findRangeById(llmAnswer, { rangeId: llmRelation.fromRangeId })!, + findRangeById(answer, { rangeId: answerRelation.fromRangeId })!, + ) && + isSameRange( + findRangeById(llmAnswer, { rangeId: llmRelation.toRangeId })!, + findRangeById(answer, { rangeId: answerRelation.toRangeId })!, + ), + ), + ).length ?? 0, + correctRelationStartAndEndWordIndexCount: + llmAnswer?.relations.filter((llmRelation) => + answer.relations.some( + (answerRelation) => + isSameRangeStartAndEndWordIndex( + findRangeById(llmAnswer, { rangeId: llmRelation.fromRangeId })!, + findRangeById(answer, { rangeId: answerRelation.fromRangeId })!, + ) && + isSameRangeStartAndEndWordIndex( + findRangeById(llmAnswer, { rangeId: llmRelation.toRangeId })!, + findRangeById(answer, { rangeId: answerRelation.toRangeId })!, + ), + ), + ).length ?? 0, + correctCoordinationCount: + llmAnswer?.coordinations.filter((llmCoordination) => + answer.coordinations.some( + (answerCoordination) => + llmCoordination.children.every( + (llmCoordinationChild) => + llmCoordinationChild.startWordIndex === + answerCoordination.children.at(llmCoordinationChild.index) + ?.startWordIndex && + llmCoordinationChild.endWordIndex === + answerCoordination.children.at(llmCoordinationChild.index) + ?.endWordIndex && + llmCoordinationChild.type === + answerCoordination.children.at(llmCoordinationChild.index) + ?.type, + ) && + llmCoordination.children.length === + answerCoordination.children.length, + ), + ).length ?? 0, + correctCoordinationStartAndEndWordIndexCount: + llmAnswer?.coordinations.filter((llmCoordination) => + answer.coordinations.some((answerCoordination) => + llmCoordination.children.every( + (llmCoordinationChild) => + llmCoordinationChild.startWordIndex === + answerCoordination.children.at(llmCoordinationChild.index) + ?.startWordIndex && + llmCoordinationChild.endWordIndex === + answerCoordination.children.at(llmCoordinationChild.index) + ?.endWordIndex, + ), + ), + ).length ?? 0, + }; +} + +function calculateMetrics( + truePositive: number, + falsePositive: number, + falseNegative: number, +) { + const recall = truePositive / (truePositive + falseNegative); + const precision = truePositive / (truePositive + falsePositive); + const f1Score = + recall === 0 && precision === 0 + ? 0 + : (2 * precision * recall) / (precision + recall); + return { + count: truePositive + falseNegative, + recall, + precision, + f1Score, + }; +} + +export function calculateOverallMetrics( + answerLlMAnswerPairs: { + answer: SentenceStructureData; + llmAnswer: SentenceStructureData | null; + }[], +) { + const compareResults = answerLlMAnswerPairs.map(({ answer, llmAnswer }) => + compareSentenceStructureData(answer, llmAnswer), + ); + + const totalResult: CompareResult = compareResults.reduce( + (accumulator, currentValue) => { + return { + answerRangeCount: + accumulator.answerRangeCount + currentValue.answerRangeCount, + answerRelationCount: + accumulator.answerRelationCount + currentValue.answerRelationCount, + answerCoordinationCount: + accumulator.answerCoordinationCount + + currentValue.answerCoordinationCount, + llmAnswerRangeCount: + accumulator.llmAnswerRangeCount + currentValue.llmAnswerRangeCount, + llmAnswerRelationCount: + accumulator.llmAnswerRelationCount + + currentValue.llmAnswerRelationCount, + llmAnswerCoordinationCount: + accumulator.llmAnswerCoordinationCount + + currentValue.llmAnswerCoordinationCount, + correctRangeCount: + accumulator.correctRangeCount + currentValue.correctRangeCount, + correctRangeStartAndEndWordIndexCount: + accumulator.correctRangeStartAndEndWordIndexCount + + currentValue.correctRangeStartAndEndWordIndexCount, + correctRelationCount: + accumulator.correctRelationCount + currentValue.correctRelationCount, + correctRelationStartAndEndWordIndexCount: + accumulator.correctRelationStartAndEndWordIndexCount + + currentValue.correctRelationStartAndEndWordIndexCount, + correctCoordinationCount: + accumulator.correctCoordinationCount + + currentValue.correctCoordinationCount, + correctCoordinationStartAndEndWordIndexCount: + accumulator.correctCoordinationStartAndEndWordIndexCount + + currentValue.correctCoordinationStartAndEndWordIndexCount, + }; + }, + { + answerRangeCount: 0, + answerRelationCount: 0, + answerCoordinationCount: 0, + llmAnswerRangeCount: 0, + llmAnswerRelationCount: 0, + llmAnswerCoordinationCount: 0, + correctRangeCount: 0, + correctRangeStartAndEndWordIndexCount: 0, + correctRelationCount: 0, + correctRelationStartAndEndWordIndexCount: 0, + correctCoordinationCount: 0, + correctCoordinationStartAndEndWordIndexCount: 0, + }, + ); + + const rangeMetrics = calculateMetrics( + totalResult.correctRangeCount, + totalResult.llmAnswerRangeCount - totalResult.correctRangeCount, + totalResult.answerRangeCount - totalResult.correctRangeCount, + ); + + const rangeStartAndEndWordIndexMetrics = calculateMetrics( + totalResult.correctRangeStartAndEndWordIndexCount, + totalResult.llmAnswerRangeCount - + totalResult.correctRangeStartAndEndWordIndexCount, + totalResult.answerRangeCount - + totalResult.correctRangeStartAndEndWordIndexCount, + ); + + const relationMetrics = calculateMetrics( + totalResult.correctRelationCount, + totalResult.llmAnswerRelationCount - totalResult.correctRelationCount, + totalResult.answerRelationCount - totalResult.correctRelationCount, + ); + + const relationStartAndEndWordIndexMetrics = calculateMetrics( + totalResult.correctRelationStartAndEndWordIndexCount, + totalResult.llmAnswerRelationCount - + totalResult.correctRelationStartAndEndWordIndexCount, + totalResult.answerRelationCount - + totalResult.correctRelationStartAndEndWordIndexCount, + ); + + const coordinationMetrics = calculateMetrics( + totalResult.correctCoordinationCount, + totalResult.llmAnswerCoordinationCount - + totalResult.correctCoordinationCount, + totalResult.answerCoordinationCount - totalResult.correctCoordinationCount, + ); + + const coordinationStartAndEndWordIndexMetrics = calculateMetrics( + totalResult.correctCoordinationStartAndEndWordIndexCount, + totalResult.llmAnswerCoordinationCount - + totalResult.correctCoordinationStartAndEndWordIndexCount, + totalResult.answerCoordinationCount - + totalResult.correctCoordinationStartAndEndWordIndexCount, + ); + + return { + generationRate: + answerLlMAnswerPairs.filter(({ llmAnswer }) => llmAnswer !== null) + .length / answerLlMAnswerPairs.length, + rangeCount: rangeMetrics.count, + rangeRecall: rangeMetrics.recall, + rangePrecision: rangeMetrics.precision, + rangeF1Score: rangeMetrics.f1Score, + rangeStartAndEndWordIndexRecall: rangeStartAndEndWordIndexMetrics.recall, + rangeStartAndEndWordIndexPrecision: + rangeStartAndEndWordIndexMetrics.precision, + rangeStartAndEndWordIndexF1Score: rangeStartAndEndWordIndexMetrics.f1Score, + relationCount: relationMetrics.count, + relationRecall: relationMetrics.recall, + relationPrecision: relationMetrics.precision, + relationF1Score: relationMetrics.f1Score, + relationStartAndEndWordIndexRecall: + relationStartAndEndWordIndexMetrics.recall, + relationStartAndEndWordIndexPrecision: + relationStartAndEndWordIndexMetrics.precision, + relationStartAndEndWordIndexF1Score: + relationStartAndEndWordIndexMetrics.f1Score, + coordinationCount: coordinationMetrics.count, + coordinationRecall: coordinationMetrics.recall, + coordinationPrecision: coordinationMetrics.precision, + coordinationF1Score: coordinationMetrics.f1Score, + coordinationStartAndEndWordIndexRecall: + coordinationStartAndEndWordIndexMetrics.recall, + coordinationStartAndEndWordIndexPrecision: + coordinationStartAndEndWordIndexMetrics.precision, + coordinationStartAndEndWordIndexF1Score: + coordinationStartAndEndWordIndexMetrics.f1Score, + }; +} diff --git a/packages/evaluation/examples.ts b/packages/evaluation/examples.ts new file mode 100644 index 0000000..62286bc --- /dev/null +++ b/packages/evaluation/examples.ts @@ -0,0 +1,718 @@ +import type { SimplifiedSentenceStructureData } from "@sentence-structure-diagram-app/sentence-structure-data"; + +export const examples: SimplifiedSentenceStructureData[] = [ + { + text: "The girl who likes to draw pictures after school has been quietly improving her skills for the past two years.", + words: [ + { + index: 0, + text: "The", + }, + { + index: 1, + text: "girl", + }, + { + index: 2, + text: "who", + }, + { + index: 3, + text: "likes", + }, + { + index: 4, + text: "to", + }, + { + index: 5, + text: "draw", + }, + { + index: 6, + text: "pictures", + }, + { + index: 7, + text: "after", + }, + { + index: 8, + text: "school", + }, + { + index: 9, + text: "has", + }, + { + index: 10, + text: "been", + }, + { + index: 11, + text: "quietly", + }, + { + index: 12, + text: "improving", + }, + { + index: 13, + text: "her", + }, + { + index: 14, + text: "skills", + }, + { + index: 15, + text: "for", + }, + { + index: 16, + text: "the", + }, + { + index: 17, + text: "past", + }, + { + index: 18, + text: "two", + }, + { + index: 19, + text: "years", + }, + { + index: 20, + text: ".", + }, + ], + ranges: [ + { + type: "文の主要素", + index: 0, + startWordIndex: 0, + endWordIndex: 1, + sentenceElementName: "S", + }, + { + type: "節", + index: 1, + startWordIndex: 2, + endWordIndex: 8, + sentenceElementName: "M", + }, + { + type: "文の主要素", + index: 2, + startWordIndex: 3, + endWordIndex: 3, + sentenceElementName: "V", + }, + { + type: "句", + index: 3, + startWordIndex: 4, + endWordIndex: 8, + sentenceElementName: "O", + }, + { + type: "文の主要素", + index: 4, + startWordIndex: 5, + endWordIndex: 5, + sentenceElementName: "V", + }, + { + type: "文の主要素", + index: 5, + startWordIndex: 6, + endWordIndex: 6, + sentenceElementName: "O", + }, + { + type: "修飾語", + index: 6, + startWordIndex: 7, + endWordIndex: 8, + sentenceElementName: "M", + }, + { + type: "文の主要素", + index: 7, + startWordIndex: 9, + endWordIndex: 12, + sentenceElementName: "V", + }, + { + type: "修飾語", + index: 8, + startWordIndex: 11, + endWordIndex: 11, + sentenceElementName: "M", + }, + { + type: "文の主要素", + index: 9, + startWordIndex: 13, + endWordIndex: 14, + sentenceElementName: "O", + }, + { + type: "修飾語", + index: 10, + startWordIndex: 15, + endWordIndex: 19, + sentenceElementName: "M", + }, + ], + relations: [ + { + fromRangeIndex: 1, + toRangeIndex: 0, + }, + ], + coordinations: [], + }, + { + text: "The detailed handwritten notes from the lesson the teacher explained on the first day were helpful for everyone.", + words: [ + { + index: 0, + text: "The", + }, + { + index: 1, + text: "detailed", + }, + { + index: 2, + text: "handwritten", + }, + { + index: 3, + text: "notes", + }, + { + index: 4, + text: "from", + }, + { + index: 5, + text: "the", + }, + { + index: 6, + text: "lesson", + }, + { + index: 7, + text: "the", + }, + { + index: 8, + text: "teacher", + }, + { + index: 9, + text: "explained", + }, + { + index: 10, + text: "on", + }, + { + index: 11, + text: "the", + }, + { + index: 12, + text: "first", + }, + { + index: 13, + text: "day", + }, + { + index: 14, + text: "were", + }, + { + index: 15, + text: "helpful", + }, + { + index: 16, + text: "for", + }, + { + index: 17, + text: "everyone", + }, + { + index: 18, + text: ".", + }, + ], + ranges: [ + { + type: "文の主要素", + index: 0, + startWordIndex: 0, + endWordIndex: 3, + sentenceElementName: "S", + }, + { + type: "修飾語", + index: 1, + startWordIndex: 4, + endWordIndex: 13, + sentenceElementName: "M", + }, + { + type: "節", + index: 2, + startWordIndex: 7, + endWordIndex: 13, + sentenceElementName: "M", + }, + { + type: "文の主要素", + index: 3, + startWordIndex: 7, + endWordIndex: 8, + sentenceElementName: "S", + }, + { + type: "文の主要素", + index: 4, + startWordIndex: 9, + endWordIndex: 9, + sentenceElementName: "V", + }, + { + type: "修飾語", + index: 5, + startWordIndex: 10, + endWordIndex: 13, + sentenceElementName: "M", + }, + { + type: "文の主要素", + index: 6, + startWordIndex: 14, + endWordIndex: 14, + sentenceElementName: "V", + }, + { + type: "文の主要素", + index: 7, + startWordIndex: 15, + endWordIndex: 15, + sentenceElementName: "C", + }, + { + type: "修飾語", + index: 8, + startWordIndex: 16, + endWordIndex: 17, + sentenceElementName: "M", + }, + { + type: "関係", + index: 9, + startWordIndex: 5, + endWordIndex: 6, + }, + ], + relations: [ + { + fromRangeIndex: 2, + toRangeIndex: 9, + }, + ], + coordinations: [], + }, + { + text: "When the weather is nice, we play soccer and visit our friends and neighbors.", + words: [ + { + index: 0, + text: "When", + }, + { + index: 1, + text: "the", + }, + { + index: 2, + text: "weather", + }, + { + index: 3, + text: "is", + }, + { + index: 4, + text: "nice", + }, + { + index: 5, + text: ",", + }, + { + index: 6, + text: "we", + }, + { + index: 7, + text: "play", + }, + { + index: 8, + text: "soccer", + }, + { + index: 9, + text: "and", + }, + { + index: 10, + text: "visit", + }, + { + index: 11, + text: "our", + }, + { + index: 12, + text: "friends", + }, + { + index: 13, + text: "and", + }, + { + index: 14, + text: "neighbors", + }, + { + index: 15, + text: ".", + }, + ], + ranges: [ + { + type: "節", + index: 0, + startWordIndex: 0, + endWordIndex: 4, + sentenceElementName: "M", + }, + { + type: "文の主要素", + index: 1, + startWordIndex: 1, + endWordIndex: 2, + sentenceElementName: "S", + }, + { + type: "文の主要素", + index: 2, + startWordIndex: 3, + endWordIndex: 3, + sentenceElementName: "V", + }, + { + type: "文の主要素", + index: 3, + startWordIndex: 4, + endWordIndex: 4, + sentenceElementName: "C", + }, + { + type: "文の主要素", + index: 4, + startWordIndex: 6, + endWordIndex: 6, + sentenceElementName: "S", + }, + { + type: "文の主要素", + index: 5, + startWordIndex: 7, + endWordIndex: 7, + sentenceElementName: "V", + }, + { + type: "文の主要素", + index: 6, + startWordIndex: 8, + endWordIndex: 8, + sentenceElementName: "O", + }, + { + type: "文の主要素", + index: 7, + startWordIndex: 10, + endWordIndex: 10, + sentenceElementName: "V", + }, + { + type: "文の主要素", + index: 8, + startWordIndex: 12, + endWordIndex: 12, + sentenceElementName: "O", + }, + { + type: "文の主要素", + index: 9, + startWordIndex: 14, + endWordIndex: 14, + sentenceElementName: "O", + }, + ], + relations: [], + coordinations: [ + { + children: [ + { + type: "並列要素", + startWordIndex: 7, + endWordIndex: 8, + }, + { + type: "等位接続詞", + startWordIndex: 9, + endWordIndex: 9, + }, + { + type: "並列要素", + startWordIndex: 10, + endWordIndex: 14, + }, + ], + }, + { + children: [ + { + type: "並列要素", + startWordIndex: 12, + endWordIndex: 12, + }, + { + type: "等位接続詞", + startWordIndex: 13, + endWordIndex: 13, + }, + { + type: "並列要素", + startWordIndex: 14, + endWordIndex: 14, + }, + ], + }, + ], + }, + { + text: "She not only bought apples, oranges, and bananas, but also got some bread on her way home.", + words: [ + { + index: 0, + text: "She", + }, + { + index: 1, + text: "not", + }, + { + index: 2, + text: "only", + }, + { + index: 3, + text: "bought", + }, + { + index: 4, + text: "apples", + }, + { + index: 5, + text: ",", + }, + { + index: 6, + text: "oranges", + }, + { + index: 7, + text: ",", + }, + { + index: 8, + text: "and", + }, + { + index: 9, + text: "bananas", + }, + { + index: 10, + text: ",", + }, + { + index: 11, + text: "but", + }, + { + index: 12, + text: "also", + }, + { + index: 13, + text: "got", + }, + { + index: 14, + text: "some", + }, + { + index: 15, + text: "bread", + }, + { + index: 16, + text: "on", + }, + { + index: 17, + text: "her", + }, + { + index: 18, + text: "way", + }, + { + index: 19, + text: "home", + }, + { + index: 20, + text: ".", + }, + ], + ranges: [ + { + type: "文の主要素", + index: 0, + startWordIndex: 0, + endWordIndex: 0, + sentenceElementName: "S", + }, + { + type: "文の主要素", + index: 1, + startWordIndex: 3, + endWordIndex: 3, + sentenceElementName: "V", + }, + { + type: "文の主要素", + index: 2, + startWordIndex: 4, + endWordIndex: 4, + sentenceElementName: "O", + }, + { + type: "文の主要素", + index: 3, + startWordIndex: 6, + endWordIndex: 6, + sentenceElementName: "O", + }, + { + type: "文の主要素", + index: 4, + startWordIndex: 9, + endWordIndex: 9, + sentenceElementName: "O", + }, + { + type: "文の主要素", + index: 5, + startWordIndex: 13, + endWordIndex: 13, + sentenceElementName: "V", + }, + { + type: "文の主要素", + index: 6, + startWordIndex: 14, + endWordIndex: 15, + sentenceElementName: "O", + }, + { + type: "修飾語", + index: 7, + startWordIndex: 16, + endWordIndex: 19, + sentenceElementName: "M", + }, + ], + relations: [], + coordinations: [ + { + children: [ + { + type: "相関接続詞", + startWordIndex: 1, + endWordIndex: 2, + }, + { + type: "並列要素", + startWordIndex: 3, + endWordIndex: 10, + }, + { + type: "相関接続詞", + startWordIndex: 11, + endWordIndex: 12, + }, + { + type: "並列要素", + startWordIndex: 13, + endWordIndex: 19, + }, + ], + }, + { + children: [ + { + type: "並列要素", + startWordIndex: 4, + endWordIndex: 5, + }, + { + type: "並列要素", + startWordIndex: 6, + endWordIndex: 7, + }, + { + type: "等位接続詞", + startWordIndex: 8, + endWordIndex: 8, + }, + { + type: "並列要素", + startWordIndex: 9, + endWordIndex: 9, + }, + ], + }, + ], + }, +] satisfies SimplifiedSentenceStructureData[]; diff --git a/packages/evaluation/generate-by-gemini.ts b/packages/evaluation/generate-by-gemini.ts new file mode 100644 index 0000000..272b91b --- /dev/null +++ b/packages/evaluation/generate-by-gemini.ts @@ -0,0 +1,159 @@ +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { sentenceStructureDataToString } from "@sentence-structure-diagram-app/sentence-structure-data"; +import { defaultConfigurations } from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; +import { generateSvgString } from "@sentence-structure-diagram-app/sentence-structure-diagram-svg"; +import { + geminiModelNames, + geminiTemperatureValues, + geminiThinkingLevelValues, + isValidGeminiParameters, + retryCount, + runCount, + type Dataset, + type GeminiLog, + type GeminiModelName, + type GeminiTemperature, + type GeminiThinkingLevel, +} from "./llmConfigurations.js"; +import { generateSentenceStructureDataByGemini } from "./generate-sentence-structure-data-by-gemini.js"; + +const args = process.argv.slice(2); +const modelName = args + .find((arg) => arg.startsWith("--model=")) + ?.split("=")[1] as GeminiModelName | undefined; +if (!modelName || !geminiModelNames.includes(modelName)) + throw new Error("Please specify a valid model name with --model="); + +type RunConfiguration = { + modelName: GeminiModelName; + temperature: GeminiTemperature; + thinkingLevel: GeminiThinkingLevel; + runIndex: number; +}; + +const runConfigurations: RunConfiguration[] = geminiTemperatureValues.flatMap( + (temperature) => + geminiThinkingLevelValues.flatMap((thinkingLevel) => { + if (!isValidGeminiParameters(modelName, temperature, thinkingLevel)) + return []; + return Array.from({ length: runCount }, (_, runIndex) => ({ + modelName, + temperature, + thinkingLevel, + runIndex, + })); + }), +); + +const datasets: Dataset[] = JSON.parse( + readFileSync(`${import.meta.dirname}/data/datasets.json`, "utf-8"), +); + +await Promise.all( + runConfigurations.map( + async ({ modelName, temperature, thinkingLevel, runIndex }) => { + const directoryPath = `${import.meta.dirname}/output/${modelName}-${temperature}-${thinkingLevel.toLowerCase()}-${runIndex}`; + if (!existsSync(directoryPath)) { + mkdirSync(directoryPath, { recursive: true }); + } + for (const dataset of datasets) { + while (true) { + const logs: GeminiLog[] = existsSync(`${directoryPath}/logs.json`) + ? JSON.parse(readFileSync(`${directoryPath}/logs.json`, "utf-8")) + : []; + const log = logs.find((log) => log.id === dataset.id) ?? null; + const retryIndex = log?.retries.length ?? 0; + if (log?.success || retryCount <= retryIndex) break; + + const startTime = Date.now(); + const result = await generateSentenceStructureDataByGemini( + dataset.englishText, + { + modelName, + temperature, + seed: runIndex * 100 + retryIndex, + thinkingLevel, + }, + ); + const endTime = Date.now(); + + if (result.success) { + writeFileSync( + `${directoryPath}/${dataset.id}.json`, + sentenceStructureDataToString(result.sentenceStructureData), + ); + writeFileSync( + `${directoryPath}/${dataset.id}.svg`, + generateSvgString( + result.sentenceStructureData, + 1500, + (text) => text.length * 8, + defaultConfigurations, + ), + ); + + const existingLog = logs.find((log) => log.id === dataset.id); + if (existingLog) { + existingLog.success = true; + existingLog.retries.push({ + success: true, + processingTime: endTime - startTime, + rawResponse: result.rawResponse, + }); + } else { + logs.push({ + id: dataset.id, + success: true, + englishText: dataset.englishText, + prompt: result.prompt, + retries: [ + { + success: true, + processingTime: endTime - startTime, + rawResponse: result.rawResponse, + }, + ], + }); + } + console.log( + `[model: ${modelName}, temperature: ${temperature}, thinkingLevel: ${thinkingLevel}, run index: ${runIndex}] Processed dataset ID ${dataset.id} successfully.`, + ); + } else { + const existingLog = logs.find((log) => log.id === dataset.id); + if (existingLog) { + existingLog.retries.push({ + success: false, + processingTime: endTime - startTime, + rawResponse: result.rawResponse, + errorMessage: result.errorMessage, + }); + } else { + logs.push({ + id: dataset.id, + success: false, + englishText: dataset.englishText, + prompt: result.prompt, + retries: [ + { + success: false, + processingTime: endTime - startTime, + rawResponse: result.rawResponse, + errorMessage: result.errorMessage, + }, + ], + }); + } + console.log( + `[model: ${modelName}, temperature: ${temperature}, thinkingLevel: ${thinkingLevel}, run index: ${runIndex}] Failed to process dataset ID ${dataset.id}. Retry index: ${retryIndex}.`, + ); + } + + writeFileSync( + `${directoryPath}/logs.json`, + JSON.stringify(logs, null, 2), + ); + } + } + }, + ), +); diff --git a/packages/evaluation/generate-by-openai.ts b/packages/evaluation/generate-by-openai.ts new file mode 100644 index 0000000..f4359b9 --- /dev/null +++ b/packages/evaluation/generate-by-openai.ts @@ -0,0 +1,158 @@ +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { sentenceStructureDataToString } from "@sentence-structure-diagram-app/sentence-structure-data"; +import { defaultConfigurations } from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; +import { generateSvgString } from "@sentence-structure-diagram-app/sentence-structure-diagram-svg"; +import { + isValidOpenAIParameters, + openAIModelNames, + openAIReasoningEffortValues, + openAIVerbosityValues, + retryCount, + runCount, + type Dataset, + type OpenAILog, + type OpenAIModelName, + type OpenAIReasoningEffort, + type OpenAIVerbosity, +} from "./llmConfigurations.js"; +import { generateSentenceStructureDataByOpenAI } from "./generate-sentence-structure-data-by-openai.js"; + +const args = process.argv.slice(2); +const modelName = args + .find((arg) => arg.startsWith("--model=")) + ?.split("=")[1] as OpenAIModelName | undefined; +if (!modelName || !openAIModelNames.includes(modelName)) + throw new Error("Please specify a valid model name with --model="); + +type RunConfiguration = { + modelName: OpenAIModelName; + reasoningEffort: OpenAIReasoningEffort; + verbosity: OpenAIVerbosity; + runIndex: number; +}; + +const runConfigurations: RunConfiguration[] = + openAIReasoningEffortValues.flatMap((reasoningEffort) => + openAIVerbosityValues.flatMap((verbosity) => { + if (!isValidOpenAIParameters(modelName, reasoningEffort, verbosity)) + return []; + return Array.from({ length: runCount }, (_, runIndex) => ({ + modelName, + reasoningEffort, + verbosity, + runIndex, + })); + }), + ); + +const datasets: Dataset[] = JSON.parse( + readFileSync(`${import.meta.dirname}/data/datasets.json`, "utf-8"), +); + +await Promise.all( + runConfigurations.map( + async ({ modelName, reasoningEffort, verbosity, runIndex }) => { + const directoryPath = `${import.meta.dirname}/output/${modelName}-${reasoningEffort}-${verbosity}-${runIndex}`; + if (!existsSync(directoryPath)) { + mkdirSync(directoryPath, { recursive: true }); + } + for (const dataset of datasets) { + while (true) { + const logs: OpenAILog[] = existsSync(`${directoryPath}/logs.json`) + ? JSON.parse(readFileSync(`${directoryPath}/logs.json`, "utf-8")) + : []; + const log = logs.find((log) => log.id === dataset.id) ?? null; + const retryIndex = log?.retries.length ?? 0; + if (log?.success || retryCount <= retryIndex) break; + + const startTime = Date.now(); + const result = await generateSentenceStructureDataByOpenAI( + dataset.englishText, + { + modelName, + reasoningEffort, + verbosity, + }, + ); + const endTime = Date.now(); + + if (result.success) { + writeFileSync( + `${directoryPath}/${dataset.id}.json`, + sentenceStructureDataToString(result.sentenceStructureData), + ); + writeFileSync( + `${directoryPath}/${dataset.id}.svg`, + generateSvgString( + result.sentenceStructureData, + 1500, + (text) => text.length * 8, + defaultConfigurations, + ), + ); + + const existingLog = logs.find((log) => log.id === dataset.id); + if (existingLog) { + existingLog.success = true; + existingLog.retries.push({ + success: true, + processingTime: endTime - startTime, + rawResponse: result.rawResponse, + }); + } else { + logs.push({ + id: dataset.id, + success: true, + englishText: dataset.englishText, + prompt: result.prompt, + retries: [ + { + success: true, + processingTime: endTime - startTime, + rawResponse: result.rawResponse, + }, + ], + }); + } + console.log( + `[model: ${modelName}, reasoning.effort: ${reasoningEffort}, verbosity: ${verbosity}, run index: ${runIndex}] Processed dataset ID ${dataset.id} successfully.`, + ); + } else { + const existingLog = logs.find((log) => log.id === dataset.id); + if (existingLog) { + existingLog.retries.push({ + success: false, + processingTime: endTime - startTime, + rawResponse: result.rawResponse, + errorMessage: result.errorMessage, + }); + } else { + logs.push({ + id: dataset.id, + success: false, + englishText: dataset.englishText, + prompt: result.prompt, + retries: [ + { + success: false, + processingTime: endTime - startTime, + rawResponse: result.rawResponse, + errorMessage: result.errorMessage, + }, + ], + }); + } + console.log( + `[model: ${modelName}, reasoning.effort: ${reasoningEffort}, verbosity: ${verbosity}, run index: ${runIndex}] Failed to process dataset ID ${dataset.id}. Retry index: ${retryIndex}.`, + ); + } + + writeFileSync( + `${directoryPath}/logs.json`, + JSON.stringify(logs, null, 2), + ); + } + } + }, + ), +); diff --git a/packages/evaluation/generate-metrics.ts b/packages/evaluation/generate-metrics.ts new file mode 100644 index 0000000..ba837dd --- /dev/null +++ b/packages/evaluation/generate-metrics.ts @@ -0,0 +1,652 @@ +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { + createSentenceStructureDataFromStringData, + type SentenceStructureData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import { + runCount, + geminiModelNames, + geminiTemperatureValues, + geminiThinkingLevelValues, + isValidGeminiParameters, + isValidOpenAIParameters, + openAIModelNames, + openAIReasoningEffortValues, + openAIVerbosityValues, + type Dataset, + type GeminiLog, + type OpenAILog, +} from "./llmConfigurations.js"; +import { calculateOverallMetrics } from "./calculate-metrics.js"; + +const datasets: Dataset[] = JSON.parse( + readFileSync(`${import.meta.dirname}/data/datasets.json`, "utf-8"), +); +const answerSentenceStructureDataList: SentenceStructureData[] = datasets.map( + (dataset) => { + const result = createSentenceStructureDataFromStringData( + readFileSync( + `${import.meta.dirname}/data/answer-${dataset.id}.json`, + "utf-8", + ), + ); + if (!result.success) throw new Error("Failed to parse answer data."); + return result.data.newSentenceStructureData; + }, +); + +const headerRow = [ + "モデル名とパラメーター", + "生成成功割合(再試行可)", + "生成成功割合(再試行不可)", + "範囲の総数", + "完全に一致した範囲のRecall(再試行可)", + "完全に一致した範囲のRecall(再試行不可)", + "完全に一致した範囲のPrecision(再試行可)", + "完全に一致した範囲のPrecision(再試行不可)", + "完全に一致した範囲のF1(再試行可)", + "完全に一致した範囲のF1(再試行不可)", + "範囲が一致した範囲のRecall(再試行可)", + "範囲が一致した範囲のRecall(再試行不可)", + "範囲が一致した範囲のPrecision(再試行可)", + "範囲が一致した範囲のPrecision(再試行不可)", + "範囲が一致した範囲のF1(再試行可)", + "範囲が一致した範囲のF1(再試行不可)", + "関係の総数", + "完全に一致した関係のRecall(再試行可)", + "完全に一致した関係のRecall(再試行不可)", + "完全に一致した関係のPrecision(再試行可)", + "完全に一致した関係のPrecision(再試行不可)", + "完全に一致した関係のF1(再試行可)", + "完全に一致した関係のF1(再試行不可)", + "範囲が一致した関係のRecall(再試行可)", + "範囲が一致した関係のRecall(再試行不可)", + "範囲が一致した関係のPrecision(再試行可)", + "範囲が一致した関係のPrecision(再試行不可)", + "範囲が一致した関係のF1(再試行可)", + "範囲が一致した関係のF1(再試行不可)", + "並列構造の総数", + "完全に一致した並列構造のRecall(再試行可)", + "完全に一致した並列構造のRecall(再試行不可)", + "完全に一致した並列構造のPrecision(再試行可)", + "完全に一致した並列構造のPrecision(再試行不可)", + "完全に一致した並列構造のF1(再試行可)", + "完全に一致した並列構造のF1(再試行不可)", + "範囲が一致した並列構造のRecall(再試行可)", + "範囲が一致した並列構造のRecall(再試行不可)", + "範囲が一致した並列構造のPrecision(再試行可)", + "範囲が一致した並列構造のPrecision(再試行不可)", + "範囲が一致した並列構造のF1(再試行可)", + "範囲が一致した並列構造のF1(再試行不可)", +]; + +const metricsCsv: string[][] = [headerRow]; + +for (const modelName of geminiModelNames) { + for (const temperature of geminiTemperatureValues) { + for (const thinkingLevel of geminiThinkingLevelValues) { + if (!isValidGeminiParameters(modelName, temperature, thinkingLevel)) + continue; + + const allTriesMetrics = Array.from( + { length: runCount }, + (_, runIndex) => { + const directoryPath = `${import.meta.dirname}/output/${modelName}-${temperature}-${thinkingLevel.toLowerCase()}-${runIndex}`; + const llmSentenceStructureDataList: (SentenceStructureData | null)[] = + datasets.map((dataset) => { + if (!existsSync(`${directoryPath}/${dataset.id}.json`)) + return null; + const result = createSentenceStructureDataFromStringData( + readFileSync(`${directoryPath}/${dataset.id}.json`, "utf-8"), + ); + if (!result.success) throw new Error("Failed to parse LLM data."); + return result.data.newSentenceStructureData; + }); + return calculateOverallMetrics( + datasets.map((_, index) => ({ + answer: answerSentenceStructureDataList.at(index)!, + llmAnswer: llmSentenceStructureDataList.at(index) ?? null, + })), + ); + }, + ).reduce( + (accumulator, currentValue) => ({ + generationRate: + accumulator.generationRate + currentValue.generationRate / runCount, + rangeCount: + accumulator.rangeCount + currentValue.rangeCount / runCount, + rangeRecall: + accumulator.rangeRecall + currentValue.rangeRecall / runCount, + rangePrecision: + accumulator.rangePrecision + currentValue.rangePrecision / runCount, + rangeF1Score: + accumulator.rangeF1Score + currentValue.rangeF1Score / runCount, + rangeStartAndEndWordIndexRecall: + accumulator.rangeStartAndEndWordIndexRecall + + currentValue.rangeStartAndEndWordIndexRecall / runCount, + rangeStartAndEndWordIndexPrecision: + accumulator.rangeStartAndEndWordIndexPrecision + + currentValue.rangeStartAndEndWordIndexPrecision / runCount, + rangeStartAndEndWordIndexF1Score: + accumulator.rangeStartAndEndWordIndexF1Score + + currentValue.rangeStartAndEndWordIndexF1Score / runCount, + relationCount: + accumulator.relationCount + currentValue.relationCount / runCount, + relationRecall: + accumulator.relationRecall + currentValue.relationRecall / runCount, + relationPrecision: + accumulator.relationPrecision + + currentValue.relationPrecision / runCount, + relationF1Score: + accumulator.relationF1Score + + currentValue.relationF1Score / runCount, + relationStartAndEndWordIndexRecall: + accumulator.relationStartAndEndWordIndexRecall + + currentValue.relationStartAndEndWordIndexRecall / runCount, + relationStartAndEndWordIndexPrecision: + accumulator.relationStartAndEndWordIndexPrecision + + currentValue.relationStartAndEndWordIndexPrecision / runCount, + relationStartAndEndWordIndexF1Score: + accumulator.relationStartAndEndWordIndexF1Score + + currentValue.relationStartAndEndWordIndexF1Score / runCount, + coordinationCount: + accumulator.coordinationCount + + currentValue.coordinationCount / runCount, + coordinationRecall: + accumulator.coordinationRecall + + currentValue.coordinationRecall / runCount, + coordinationPrecision: + accumulator.coordinationPrecision + + currentValue.coordinationPrecision / runCount, + coordinationF1Score: + accumulator.coordinationF1Score + + currentValue.coordinationF1Score / runCount, + coordinationStartAndEndWordIndexRecall: + accumulator.coordinationStartAndEndWordIndexRecall + + currentValue.coordinationStartAndEndWordIndexRecall / runCount, + coordinationStartAndEndWordIndexPrecision: + accumulator.coordinationStartAndEndWordIndexPrecision + + currentValue.coordinationStartAndEndWordIndexPrecision / runCount, + coordinationStartAndEndWordIndexF1Score: + accumulator.coordinationStartAndEndWordIndexF1Score + + currentValue.coordinationStartAndEndWordIndexF1Score / runCount, + }), + { + generationRate: 0, + rangeCount: 0, + rangeRecall: 0, + rangePrecision: 0, + rangeF1Score: 0, + rangeStartAndEndWordIndexRecall: 0, + rangeStartAndEndWordIndexPrecision: 0, + rangeStartAndEndWordIndexF1Score: 0, + relationCount: 0, + relationRecall: 0, + relationPrecision: 0, + relationF1Score: 0, + relationStartAndEndWordIndexRecall: 0, + relationStartAndEndWordIndexPrecision: 0, + relationStartAndEndWordIndexF1Score: 0, + coordinationCount: 0, + coordinationRecall: 0, + coordinationPrecision: 0, + coordinationF1Score: 0, + coordinationStartAndEndWordIndexRecall: 0, + coordinationStartAndEndWordIndexPrecision: 0, + coordinationStartAndEndWordIndexF1Score: 0, + }, + ); + + const firstTryMetrics = Array.from( + { length: runCount }, + (_, runIndex) => { + const directoryPath = `${import.meta.dirname}/output/${modelName}-${temperature}-${thinkingLevel.toLowerCase()}-${runIndex}`; + const logs: GeminiLog[] | null = existsSync( + `${directoryPath}/logs.json`, + ) + ? JSON.parse(readFileSync(`${directoryPath}/logs.json`, "utf-8")) + : null; + const llmSentenceStructureDataList: (SentenceStructureData | null)[] = + datasets.map((dataset) => { + const log = logs?.find((log) => log.id === dataset.id); + if ( + !existsSync(`${directoryPath}/${dataset.id}.json`) || + !log || + 1 < log.retries.length + ) + return null; + const result = createSentenceStructureDataFromStringData( + readFileSync(`${directoryPath}/${dataset.id}.json`, "utf-8"), + ); + if (!result.success) throw new Error("Failed to parse LLM data."); + return result.data.newSentenceStructureData; + }); + return calculateOverallMetrics( + datasets.map((_, index) => ({ + answer: answerSentenceStructureDataList.at(index)!, + llmAnswer: llmSentenceStructureDataList.at(index) ?? null, + })), + ); + }, + ).reduce( + (accumulator, currentValue) => ({ + generationRate: + accumulator.generationRate + currentValue.generationRate / runCount, + rangeCount: + accumulator.rangeCount + currentValue.rangeCount / runCount, + rangeRecall: + accumulator.rangeRecall + currentValue.rangeRecall / runCount, + rangePrecision: + accumulator.rangePrecision + currentValue.rangePrecision / runCount, + rangeF1Score: + accumulator.rangeF1Score + currentValue.rangeF1Score / runCount, + rangeStartAndEndWordIndexRecall: + accumulator.rangeStartAndEndWordIndexRecall + + currentValue.rangeStartAndEndWordIndexRecall / runCount, + rangeStartAndEndWordIndexPrecision: + accumulator.rangeStartAndEndWordIndexPrecision + + currentValue.rangeStartAndEndWordIndexPrecision / runCount, + rangeStartAndEndWordIndexF1Score: + accumulator.rangeStartAndEndWordIndexF1Score + + currentValue.rangeStartAndEndWordIndexF1Score / runCount, + relationCount: + accumulator.relationCount + currentValue.relationCount / runCount, + relationRecall: + accumulator.relationRecall + currentValue.relationRecall / runCount, + relationPrecision: + accumulator.relationPrecision + + currentValue.relationPrecision / runCount, + relationF1Score: + accumulator.relationF1Score + + currentValue.relationF1Score / runCount, + relationStartAndEndWordIndexRecall: + accumulator.relationStartAndEndWordIndexRecall + + currentValue.relationStartAndEndWordIndexRecall / runCount, + relationStartAndEndWordIndexPrecision: + accumulator.relationStartAndEndWordIndexPrecision + + currentValue.relationStartAndEndWordIndexPrecision / runCount, + relationStartAndEndWordIndexF1Score: + accumulator.relationStartAndEndWordIndexF1Score + + currentValue.relationStartAndEndWordIndexF1Score / runCount, + coordinationCount: + accumulator.coordinationCount + + currentValue.coordinationCount / runCount, + coordinationRecall: + accumulator.coordinationRecall + + currentValue.coordinationRecall / runCount, + coordinationPrecision: + accumulator.coordinationPrecision + + currentValue.coordinationPrecision / runCount, + coordinationF1Score: + accumulator.coordinationF1Score + + currentValue.coordinationF1Score / runCount, + coordinationStartAndEndWordIndexRecall: + accumulator.coordinationStartAndEndWordIndexRecall + + currentValue.coordinationStartAndEndWordIndexRecall / runCount, + coordinationStartAndEndWordIndexPrecision: + accumulator.coordinationStartAndEndWordIndexPrecision + + currentValue.coordinationStartAndEndWordIndexPrecision / runCount, + coordinationStartAndEndWordIndexF1Score: + accumulator.coordinationStartAndEndWordIndexF1Score + + currentValue.coordinationStartAndEndWordIndexF1Score / runCount, + }), + { + generationRate: 0, + rangeCount: 0, + rangeRecall: 0, + rangePrecision: 0, + rangeF1Score: 0, + rangeStartAndEndWordIndexRecall: 0, + rangeStartAndEndWordIndexPrecision: 0, + rangeStartAndEndWordIndexF1Score: 0, + relationCount: 0, + relationRecall: 0, + relationPrecision: 0, + relationF1Score: 0, + relationStartAndEndWordIndexRecall: 0, + relationStartAndEndWordIndexPrecision: 0, + relationStartAndEndWordIndexF1Score: 0, + coordinationCount: 0, + coordinationRecall: 0, + coordinationPrecision: 0, + coordinationF1Score: 0, + coordinationStartAndEndWordIndexRecall: 0, + coordinationStartAndEndWordIndexPrecision: 0, + coordinationStartAndEndWordIndexF1Score: 0, + }, + ); + + metricsCsv.push([ + `${modelName} temperature=${temperature} thinkingLevel=${thinkingLevel}`, + allTriesMetrics.generationRate.toFixed(3), + firstTryMetrics.generationRate.toFixed(3), + allTriesMetrics.rangeCount.toString(), + allTriesMetrics.rangeRecall.toFixed(3), + firstTryMetrics.rangeRecall.toFixed(3), + allTriesMetrics.rangePrecision.toFixed(3), + firstTryMetrics.rangePrecision.toFixed(3), + allTriesMetrics.rangeF1Score.toFixed(3), + firstTryMetrics.rangeF1Score.toFixed(3), + allTriesMetrics.rangeStartAndEndWordIndexRecall.toFixed(3), + firstTryMetrics.rangeStartAndEndWordIndexRecall.toFixed(3), + allTriesMetrics.rangeStartAndEndWordIndexPrecision.toFixed(3), + firstTryMetrics.rangeStartAndEndWordIndexPrecision.toFixed(3), + allTriesMetrics.rangeStartAndEndWordIndexF1Score.toFixed(3), + firstTryMetrics.rangeStartAndEndWordIndexF1Score.toFixed(3), + allTriesMetrics.relationCount.toString(), + allTriesMetrics.relationRecall.toFixed(3), + firstTryMetrics.relationRecall.toFixed(3), + allTriesMetrics.relationPrecision.toFixed(3), + firstTryMetrics.relationPrecision.toFixed(3), + allTriesMetrics.relationF1Score.toFixed(3), + firstTryMetrics.relationF1Score.toFixed(3), + allTriesMetrics.relationStartAndEndWordIndexRecall.toFixed(3), + firstTryMetrics.relationStartAndEndWordIndexRecall.toFixed(3), + allTriesMetrics.relationStartAndEndWordIndexPrecision.toFixed(3), + firstTryMetrics.relationStartAndEndWordIndexPrecision.toFixed(3), + allTriesMetrics.relationStartAndEndWordIndexF1Score.toFixed(3), + firstTryMetrics.relationStartAndEndWordIndexF1Score.toFixed(3), + allTriesMetrics.coordinationCount.toString(), + allTriesMetrics.coordinationRecall.toFixed(3), + firstTryMetrics.coordinationRecall.toFixed(3), + allTriesMetrics.coordinationPrecision.toFixed(3), + firstTryMetrics.coordinationPrecision.toFixed(3), + allTriesMetrics.coordinationF1Score.toFixed(3), + firstTryMetrics.coordinationF1Score.toFixed(3), + allTriesMetrics.coordinationStartAndEndWordIndexRecall.toFixed(3), + firstTryMetrics.coordinationStartAndEndWordIndexRecall.toFixed(3), + allTriesMetrics.coordinationStartAndEndWordIndexPrecision.toFixed(3), + firstTryMetrics.coordinationStartAndEndWordIndexPrecision.toFixed(3), + allTriesMetrics.coordinationStartAndEndWordIndexF1Score.toFixed(3), + firstTryMetrics.coordinationStartAndEndWordIndexF1Score.toFixed(3), + ]); + } + } +} + +for (const modelName of openAIModelNames) { + for (const reasoningEffort of openAIReasoningEffortValues) { + for (const verbosity of openAIVerbosityValues) { + if (!isValidOpenAIParameters(modelName, reasoningEffort, verbosity)) + continue; + + const allTriesMetrics = Array.from( + { length: runCount }, + (_, runIndex) => { + const directoryPath = `${import.meta.dirname}/output/${modelName}-${reasoningEffort}-${verbosity}-${runIndex}`; + const llmSentenceStructureDataList: (SentenceStructureData | null)[] = + datasets.map((dataset) => { + if (!existsSync(`${directoryPath}/${dataset.id}.json`)) + return null; + const result = createSentenceStructureDataFromStringData( + readFileSync(`${directoryPath}/${dataset.id}.json`, "utf-8"), + ); + if (!result.success) throw new Error("Failed to parse LLM data."); + return result.data.newSentenceStructureData; + }); + return calculateOverallMetrics( + datasets.map((_, index) => ({ + answer: answerSentenceStructureDataList.at(index)!, + llmAnswer: llmSentenceStructureDataList.at(index) ?? null, + })), + ); + }, + ).reduce( + (accumulator, currentValue) => ({ + generationRate: + accumulator.generationRate + currentValue.generationRate / runCount, + rangeCount: + accumulator.rangeCount + currentValue.rangeCount / runCount, + rangeRecall: + accumulator.rangeRecall + currentValue.rangeRecall / runCount, + rangePrecision: + accumulator.rangePrecision + currentValue.rangePrecision / runCount, + rangeF1Score: + accumulator.rangeF1Score + currentValue.rangeF1Score / runCount, + rangeStartAndEndWordIndexRecall: + accumulator.rangeStartAndEndWordIndexRecall + + currentValue.rangeStartAndEndWordIndexRecall / runCount, + rangeStartAndEndWordIndexPrecision: + accumulator.rangeStartAndEndWordIndexPrecision + + currentValue.rangeStartAndEndWordIndexPrecision / runCount, + rangeStartAndEndWordIndexF1Score: + accumulator.rangeStartAndEndWordIndexF1Score + + currentValue.rangeStartAndEndWordIndexF1Score / runCount, + relationCount: + accumulator.relationCount + currentValue.relationCount / runCount, + relationRecall: + accumulator.relationRecall + currentValue.relationRecall / runCount, + relationPrecision: + accumulator.relationPrecision + + currentValue.relationPrecision / runCount, + relationF1Score: + accumulator.relationF1Score + + currentValue.relationF1Score / runCount, + relationStartAndEndWordIndexRecall: + accumulator.relationStartAndEndWordIndexRecall + + currentValue.relationStartAndEndWordIndexRecall / runCount, + relationStartAndEndWordIndexPrecision: + accumulator.relationStartAndEndWordIndexPrecision + + currentValue.relationStartAndEndWordIndexPrecision / runCount, + relationStartAndEndWordIndexF1Score: + accumulator.relationStartAndEndWordIndexF1Score + + currentValue.relationStartAndEndWordIndexF1Score / runCount, + coordinationCount: + accumulator.coordinationCount + + currentValue.coordinationCount / runCount, + coordinationRecall: + accumulator.coordinationRecall + + currentValue.coordinationRecall / runCount, + coordinationPrecision: + accumulator.coordinationPrecision + + currentValue.coordinationPrecision / runCount, + coordinationF1Score: + accumulator.coordinationF1Score + + currentValue.coordinationF1Score / runCount, + coordinationStartAndEndWordIndexRecall: + accumulator.coordinationStartAndEndWordIndexRecall + + currentValue.coordinationStartAndEndWordIndexRecall / runCount, + coordinationStartAndEndWordIndexPrecision: + accumulator.coordinationStartAndEndWordIndexPrecision + + currentValue.coordinationStartAndEndWordIndexPrecision / runCount, + coordinationStartAndEndWordIndexF1Score: + accumulator.coordinationStartAndEndWordIndexF1Score + + currentValue.coordinationStartAndEndWordIndexF1Score / runCount, + }), + { + generationRate: 0, + rangeCount: 0, + rangeRecall: 0, + rangePrecision: 0, + rangeF1Score: 0, + rangeStartAndEndWordIndexRecall: 0, + rangeStartAndEndWordIndexPrecision: 0, + rangeStartAndEndWordIndexF1Score: 0, + relationCount: 0, + relationRecall: 0, + relationPrecision: 0, + relationF1Score: 0, + relationStartAndEndWordIndexRecall: 0, + relationStartAndEndWordIndexPrecision: 0, + relationStartAndEndWordIndexF1Score: 0, + coordinationCount: 0, + coordinationRecall: 0, + coordinationPrecision: 0, + coordinationF1Score: 0, + coordinationStartAndEndWordIndexRecall: 0, + coordinationStartAndEndWordIndexPrecision: 0, + coordinationStartAndEndWordIndexF1Score: 0, + }, + ); + + const firstTryMetrics = Array.from( + { length: runCount }, + (_, runIndex) => { + const directoryPath = `${import.meta.dirname}/output/${modelName}-${reasoningEffort}-${verbosity}-${runIndex}`; + const logs: OpenAILog[] | null = existsSync( + `${directoryPath}/logs.json`, + ) + ? JSON.parse(readFileSync(`${directoryPath}/logs.json`, "utf-8")) + : null; + const llmSentenceStructureDataList: (SentenceStructureData | null)[] = + datasets.map((dataset) => { + const log = logs?.find((log) => log.id === dataset.id); + if ( + !existsSync(`${directoryPath}/${dataset.id}.json`) || + !log || + 1 < log.retries.length + ) + return null; + const result = createSentenceStructureDataFromStringData( + readFileSync(`${directoryPath}/${dataset.id}.json`, "utf-8"), + ); + if (!result.success) throw new Error("Failed to parse LLM data."); + return result.data.newSentenceStructureData; + }); + return calculateOverallMetrics( + datasets.map((_, index) => ({ + answer: answerSentenceStructureDataList.at(index)!, + llmAnswer: llmSentenceStructureDataList.at(index) ?? null, + })), + ); + }, + ).reduce( + (accumulator, currentValue) => ({ + generationRate: + accumulator.generationRate + currentValue.generationRate / runCount, + rangeCount: + accumulator.rangeCount + currentValue.rangeCount / runCount, + rangeRecall: + accumulator.rangeRecall + currentValue.rangeRecall / runCount, + rangePrecision: + accumulator.rangePrecision + currentValue.rangePrecision / runCount, + rangeF1Score: + accumulator.rangeF1Score + currentValue.rangeF1Score / runCount, + rangeStartAndEndWordIndexRecall: + accumulator.rangeStartAndEndWordIndexRecall + + currentValue.rangeStartAndEndWordIndexRecall / runCount, + rangeStartAndEndWordIndexPrecision: + accumulator.rangeStartAndEndWordIndexPrecision + + currentValue.rangeStartAndEndWordIndexPrecision / runCount, + rangeStartAndEndWordIndexF1Score: + accumulator.rangeStartAndEndWordIndexF1Score + + currentValue.rangeStartAndEndWordIndexF1Score / runCount, + relationCount: + accumulator.relationCount + currentValue.relationCount / runCount, + relationRecall: + accumulator.relationRecall + currentValue.relationRecall / runCount, + relationPrecision: + accumulator.relationPrecision + + currentValue.relationPrecision / runCount, + relationF1Score: + accumulator.relationF1Score + + currentValue.relationF1Score / runCount, + relationStartAndEndWordIndexRecall: + accumulator.relationStartAndEndWordIndexRecall + + currentValue.relationStartAndEndWordIndexRecall / runCount, + relationStartAndEndWordIndexPrecision: + accumulator.relationStartAndEndWordIndexPrecision + + currentValue.relationStartAndEndWordIndexPrecision / runCount, + relationStartAndEndWordIndexF1Score: + accumulator.relationStartAndEndWordIndexF1Score + + currentValue.relationStartAndEndWordIndexF1Score / runCount, + coordinationCount: + accumulator.coordinationCount + + currentValue.coordinationCount / runCount, + coordinationRecall: + accumulator.coordinationRecall + + currentValue.coordinationRecall / runCount, + coordinationPrecision: + accumulator.coordinationPrecision + + currentValue.coordinationPrecision / runCount, + coordinationF1Score: + accumulator.coordinationF1Score + + currentValue.coordinationF1Score / runCount, + coordinationStartAndEndWordIndexRecall: + accumulator.coordinationStartAndEndWordIndexRecall + + currentValue.coordinationStartAndEndWordIndexRecall / runCount, + coordinationStartAndEndWordIndexPrecision: + accumulator.coordinationStartAndEndWordIndexPrecision + + currentValue.coordinationStartAndEndWordIndexPrecision / runCount, + coordinationStartAndEndWordIndexF1Score: + accumulator.coordinationStartAndEndWordIndexF1Score + + currentValue.coordinationStartAndEndWordIndexF1Score / runCount, + }), + { + generationRate: 0, + rangeCount: 0, + rangeRecall: 0, + rangePrecision: 0, + rangeF1Score: 0, + rangeStartAndEndWordIndexRecall: 0, + rangeStartAndEndWordIndexPrecision: 0, + rangeStartAndEndWordIndexF1Score: 0, + relationCount: 0, + relationRecall: 0, + relationPrecision: 0, + relationF1Score: 0, + relationStartAndEndWordIndexRecall: 0, + relationStartAndEndWordIndexPrecision: 0, + relationStartAndEndWordIndexF1Score: 0, + coordinationCount: 0, + coordinationRecall: 0, + coordinationPrecision: 0, + coordinationF1Score: 0, + coordinationStartAndEndWordIndexRecall: 0, + coordinationStartAndEndWordIndexPrecision: 0, + coordinationStartAndEndWordIndexF1Score: 0, + }, + ); + + metricsCsv.push([ + `${modelName} reasoning.effort=${reasoningEffort} verbosity=${verbosity}`, + allTriesMetrics.generationRate.toFixed(3), + firstTryMetrics.generationRate.toFixed(3), + allTriesMetrics.rangeCount.toString(), + allTriesMetrics.rangeRecall.toFixed(3), + firstTryMetrics.rangeRecall.toFixed(3), + allTriesMetrics.rangePrecision.toFixed(3), + firstTryMetrics.rangePrecision.toFixed(3), + allTriesMetrics.rangeF1Score.toFixed(3), + firstTryMetrics.rangeF1Score.toFixed(3), + allTriesMetrics.rangeStartAndEndWordIndexRecall.toFixed(3), + firstTryMetrics.rangeStartAndEndWordIndexRecall.toFixed(3), + allTriesMetrics.rangeStartAndEndWordIndexPrecision.toFixed(3), + firstTryMetrics.rangeStartAndEndWordIndexPrecision.toFixed(3), + allTriesMetrics.rangeStartAndEndWordIndexF1Score.toFixed(3), + firstTryMetrics.rangeStartAndEndWordIndexF1Score.toFixed(3), + allTriesMetrics.relationCount.toString(), + allTriesMetrics.relationRecall.toFixed(3), + firstTryMetrics.relationRecall.toFixed(3), + allTriesMetrics.relationPrecision.toFixed(3), + firstTryMetrics.relationPrecision.toFixed(3), + allTriesMetrics.relationF1Score.toFixed(3), + firstTryMetrics.relationF1Score.toFixed(3), + allTriesMetrics.relationStartAndEndWordIndexRecall.toFixed(3), + firstTryMetrics.relationStartAndEndWordIndexRecall.toFixed(3), + allTriesMetrics.relationStartAndEndWordIndexPrecision.toFixed(3), + firstTryMetrics.relationStartAndEndWordIndexPrecision.toFixed(3), + allTriesMetrics.relationStartAndEndWordIndexF1Score.toFixed(3), + firstTryMetrics.relationStartAndEndWordIndexF1Score.toFixed(3), + allTriesMetrics.coordinationCount.toString(), + allTriesMetrics.coordinationRecall.toFixed(3), + firstTryMetrics.coordinationRecall.toFixed(3), + allTriesMetrics.coordinationPrecision.toFixed(3), + firstTryMetrics.coordinationPrecision.toFixed(3), + allTriesMetrics.coordinationF1Score.toFixed(3), + firstTryMetrics.coordinationF1Score.toFixed(3), + allTriesMetrics.coordinationStartAndEndWordIndexRecall.toFixed(3), + firstTryMetrics.coordinationStartAndEndWordIndexRecall.toFixed(3), + allTriesMetrics.coordinationStartAndEndWordIndexPrecision.toFixed(3), + firstTryMetrics.coordinationStartAndEndWordIndexPrecision.toFixed(3), + allTriesMetrics.coordinationStartAndEndWordIndexF1Score.toFixed(3), + firstTryMetrics.coordinationStartAndEndWordIndexF1Score.toFixed(3), + ]); + } + } +} + +writeFileSync( + `${import.meta.dirname}/output/metrics.csv`, + metricsCsv.map((row) => row.join(",")).join("\n"), +); diff --git a/packages/evaluation/generate-sentence-structure-data-by-gemini.ts b/packages/evaluation/generate-sentence-structure-data-by-gemini.ts new file mode 100644 index 0000000..882dddd --- /dev/null +++ b/packages/evaluation/generate-sentence-structure-data-by-gemini.ts @@ -0,0 +1,94 @@ +import { + GenerateContentResponse, + GoogleGenAI, + ThinkingLevel, +} from "@google/genai"; +import { + createSentenceStructureDataFromSimplifiedAnnotationData, + createSentenceStructureDataFromText, + type SentenceStructureData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import type { + GeminiModelName, + GeminiTemperature, + GeminiThinkingLevel, +} from "./llmConfigurations.js"; +import { generateGeminiPrompt, type Prompt } from "./prompt.js"; + +const ai = new GoogleGenAI({}); + +export async function generateSentenceStructureDataByGemini( + text: string, + parameters: { + modelName: GeminiModelName; + temperature: GeminiTemperature; + seed: number; + thinkingLevel: GeminiThinkingLevel; + }, +): Promise< + | { + success: true; + prompt: Prompt; + rawResponse: GenerateContentResponse; + sentenceStructureData: SentenceStructureData; + } + | { + success: false; + prompt: Prompt; + rawResponse: GenerateContentResponse; + errorMessage: string; + } +> { + const prompt = generateGeminiPrompt( + text, + createSentenceStructureDataFromText({ + text, + }).words.map((word) => word.text), + ); + const response = await ai.models.generateContent({ + model: parameters.modelName, + contents: prompt.userInput, + config: { + systemInstruction: prompt.systemInstruction, + responseMimeType: "application/json", + temperature: parameters.temperature, + seed: parameters.seed, + ...((parameters.modelName === "gemini-3-pro-preview" || + parameters.modelName === "gemini-3-flash-preview") && { + thinkingConfig: { + thinkingLevel: ThinkingLevel[parameters.thinkingLevel], + }, + }), + }, + }); + try { + if (!response.text) throw new Error("AI returned no result"); + const json = (() => { + try { + return JSON.parse(response.text); + } catch { + throw new Error("AI returned invalid JSON"); + } + })(); + const sentenceStructureData = + createSentenceStructureDataFromSimplifiedAnnotationData(text, json); + if (sentenceStructureData.success) { + return { + success: true, + prompt, + rawResponse: response, + sentenceStructureData: + sentenceStructureData.data.newSentenceStructureData, + }; + } else { + throw new Error("AI returned JSON with invalid schema"); + } + } catch (error) { + return { + success: false, + prompt, + rawResponse: response, + errorMessage: error instanceof Error ? error.message : "", + }; + } +} diff --git a/packages/evaluation/generate-sentence-structure-data-by-llama.ts b/packages/evaluation/generate-sentence-structure-data-by-llama.ts new file mode 100644 index 0000000..8c16b05 --- /dev/null +++ b/packages/evaluation/generate-sentence-structure-data-by-llama.ts @@ -0,0 +1,51 @@ +// import { AzureOpenAI } from "openai"; +// import { +// SimplifiedAnnotationDataSchema, +// type SimplifiedAnnotationData, +// } from "@sentence-structure-diagram-app/sentence-structure-data"; +// import { InvalidAIOutputError } from "./invalid-ai-output-error.js"; + +// export async function generateSimplifiedAnnotationDataByLlama( +// prompt: [ +// { +// role: "system"; +// content: string; +// }, +// { +// role: "user"; +// content: string; +// }, +// ], +// ): Promise { +// const client = new AzureOpenAI({ +// endpoint: process.env.AZURE_OPENAI_ENDPOINT, +// apiKey: process.env.AZURE_OPENAI_API_KEY, +// apiVersion: process.env.AZURE_OPENAI_API_VERSION, +// }); + +// try { +// const completion = await client.chat.completions.parse({ +// model: process.env.AZURE_OPENAI_LLAMA4_DEPLOYMENT_NAME!, +// messages: prompt, +// response_format: { type: "json_object" }, +// }); +// const result = completion.choices[0]?.message.content; +// if (!result) throw new InvalidAIOutputError("AI returned no result"); +// const json = (() => { +// try { +// return JSON.parse(result); +// } catch { +// throw new InvalidAIOutputError("AI returned invalid JSON"); +// } +// })(); +// console.log("Generated JSON:", JSON.stringify(json, null, 2)); +// try { +// return SimplifiedAnnotationDataSchema.parse(json); +// } catch { +// throw new InvalidAIOutputError("AI returned JSON with invalid schema"); +// } +// } catch (error) { +// console.error(error); +// throw error; +// } +// } diff --git a/packages/evaluation/generate-sentence-structure-data-by-openai.ts b/packages/evaluation/generate-sentence-structure-data-by-openai.ts new file mode 100644 index 0000000..35669f2 --- /dev/null +++ b/packages/evaluation/generate-sentence-structure-data-by-openai.ts @@ -0,0 +1,95 @@ +import { AzureOpenAI } from "openai"; +import { zodTextFormat } from "openai/helpers/zod.js"; +import type { ParsedResponse } from "openai/resources/responses/responses.js"; +import { + createSentenceStructureDataFromSimplifiedAnnotationData, + createSentenceStructureDataFromText, + SimplifiedAnnotationDataSchema, + type SentenceStructureData, + type SimplifiedAnnotationData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import type { + OpenAIModelName, + OpenAIReasoningEffort, + OpenAIVerbosity, +} from "./llmConfigurations.js"; +import { generateGPTPrompt, type Prompt } from "./prompt.js"; + +const client = new AzureOpenAI({ + endpoint: process.env.AZURE_OPENAI_ENDPOINT, + apiKey: process.env.AZURE_OPENAI_API_KEY, + apiVersion: process.env.AZURE_OPENAI_API_VERSION, +}); + +export async function generateSentenceStructureDataByOpenAI( + text: string, + parameters: { + modelName: OpenAIModelName; + reasoningEffort: OpenAIReasoningEffort; + verbosity: OpenAIVerbosity; + }, +): Promise< + | { + success: true; + prompt: Prompt; + rawResponse: ParsedResponse; + sentenceStructureData: SentenceStructureData; + } + | { + success: false; + prompt: Prompt; + rawResponse: ParsedResponse; + errorMessage: string; + } +> { + const prompt = generateGPTPrompt( + text, + createSentenceStructureDataFromText({ + text, + }).words.map((word) => word.text), + ); + const response = await client.responses.parse({ + model: + parameters.modelName === "gpt-5" + ? process.env.AZURE_OPENAI_GPT5_DEPLOYMENT_NAME! + : parameters.modelName === "gpt-5.1" + ? process.env.AZURE_OPENAI_GPT5_1_DEPLOYMENT_NAME! + : process.env.AZURE_OPENAI_GPT5_2_DEPLOYMENT_NAME!, + instructions: prompt.systemInstruction, + reasoning: { effort: parameters.reasoningEffort }, + input: prompt.userInput, + text: { + verbosity: parameters.verbosity, + format: zodTextFormat( + SimplifiedAnnotationDataSchema, + "simplified-annotation-data", + ), + }, + }); + try { + if (!response.output_parsed) throw new Error("AI returned no result"); + const sentenceStructureData = + createSentenceStructureDataFromSimplifiedAnnotationData( + text, + response.output_parsed, + ); + if (sentenceStructureData.success) { + return { + success: true, + prompt, + rawResponse: response, + sentenceStructureData: + sentenceStructureData.data.newSentenceStructureData, + }; + } else { + throw new Error("AI returned JSON with invalid schema"); + } + } catch (error) { + return { + success: false, + prompt, + rawResponse: response, + errorMessage: error instanceof Error ? error.message : "", + }; + } +} diff --git a/packages/evaluation/index.ts b/packages/evaluation/index.ts new file mode 100644 index 0000000..958b5e1 --- /dev/null +++ b/packages/evaluation/index.ts @@ -0,0 +1,5 @@ +export { + generateGeminiPrompt, + generateGPTPrompt, + type Prompt, +} from "./prompt.js"; diff --git a/packages/evaluation/llmConfigurations.ts b/packages/evaluation/llmConfigurations.ts new file mode 100644 index 0000000..82e4c2e --- /dev/null +++ b/packages/evaluation/llmConfigurations.ts @@ -0,0 +1,110 @@ +import type { GenerateContentResponse } from "@google/genai"; +import type { ParsedResponse } from "openai/resources/responses/responses.js"; +import type { SimplifiedAnnotationData } from "@sentence-structure-diagram-app/sentence-structure-data"; +import type { Prompt } from "./prompt.js"; + +export type Dataset = { + id: number; + englishText: string; +}; + +export const runCount = 5; +export const retryCount = 10; + +export const geminiModelNames = [ + "gemini-2.5-flash-lite", + "gemini-2.5-flash", + "gemini-2.5-pro", + "gemini-3-flash-preview", + "gemini-3-pro-preview", +] as const; +export type GeminiModelName = (typeof geminiModelNames)[number]; +export const geminiTemperatureValues = [0, 0.5, 1, 1.5, 2] as const; +export type GeminiTemperature = (typeof geminiTemperatureValues)[number]; +export const geminiThinkingLevelValues = ["LOW", "HIGH"] as const; +export type GeminiThinkingLevel = (typeof geminiThinkingLevelValues)[number]; + +export function isValidGeminiParameters( + modelName: GeminiModelName, + temperature: GeminiTemperature, + thinkingLevel: GeminiThinkingLevel, +): boolean { + // Gemini 3以前ではthinkingLevelにLOWは指定できない cf. https://ai.google.dev/api/generate-content#ThinkingConfig + if ( + (modelName === "gemini-2.5-pro" || + modelName === "gemini-2.5-flash" || + modelName === "gemini-2.5-flash-lite") && + thinkingLevel === "LOW" + ) { + return false; + } + // レート制限回避のため、最小限の組み合わせのみ許可 + if (modelName === "gemini-3-pro-preview" && temperature !== 1) { + return false; + } + return true; +} + +export type GeminiLog = { + id: number; + success: boolean; + englishText: string; + prompt: Prompt; + retries: ( + | { + success: true; + processingTime: number; + rawResponse: GenerateContentResponse; + } + | { + success: false; + processingTime: number; + rawResponse: GenerateContentResponse; + errorMessage: string; + } + )[]; +}; + +export const openAIModelNames = ["gpt-5", "gpt-5.1", "gpt-5.2"] as const; +export const openAIReasoningEffortValues = [ + "none", + "low", + "medium", + "high", +] as const; +export const openAIVerbosityValues = ["low", "medium", "high"] as const; + +export type OpenAIModelName = (typeof openAIModelNames)[number]; +export type OpenAIReasoningEffort = + (typeof openAIReasoningEffortValues)[number]; +export type OpenAIVerbosity = (typeof openAIVerbosityValues)[number]; + +export function isValidOpenAIParameters( + modelName: OpenAIModelName, + reasoningEffort: OpenAIReasoningEffort, + verbosity: OpenAIVerbosity, +): boolean { + // gpt-5ではreasoning.effortにnoneは指定できない cf. https://platform.openai.com/docs/api-reference/responses/create#responses_create-reasoning-effort + if (modelName === "gpt-5" && reasoningEffort === "none") return false; + return true; +} + +export type OpenAILog = { + id: number; + success: boolean; + englishText: string; + prompt: Prompt; + retries: ( + | { + success: true; + processingTime: number; + rawResponse: ParsedResponse; + } + | { + success: false; + processingTime: number; + rawResponse: ParsedResponse; + errorMessage: string; + } + )[]; +}; diff --git a/packages/evaluation/package.json b/packages/evaluation/package.json new file mode 100644 index 0000000..542bfa7 --- /dev/null +++ b/packages/evaluation/package.json @@ -0,0 +1,24 @@ +{ + "name": "@sentence-structure-diagram-app/evaluation", + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "clean": "rm -r dist" + }, + "dependencies": { + "@google/genai": "^1.34.0", + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-configurations": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-svg": "^0.1.0", + "openai": "^6.15.0", + "zod": "^4.2.1" + }, + "devDependencies": { + "@types/node": "^24.10.4", + "tsx": "^4.21.0", + "typescript": "^5.9.3" + } +} diff --git a/packages/evaluation/prompt.ts b/packages/evaluation/prompt.ts new file mode 100644 index 0000000..2546869 --- /dev/null +++ b/packages/evaluation/prompt.ts @@ -0,0 +1,121 @@ +import * as z from "zod"; +import { + SimplifiedAnnotationDataSchema, + type SimplifiedAnnotationData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import { examples } from "./examples.js"; + +export type Prompt = { + systemInstruction: string; + userInput: string; +}; + +const instructionText = `\ +あなたは学習者向けに英文の構造を解析する専門家です。 +これから英文を与えます。また、その英文の単語とそれに対応するインデックスの関係を与えます。 +与えられた英文の構造を解析し、与えられたJSON Schemaに従ったJSONデータを生成してください。 + +## 要件 + +- 単語とそれに対応するインデックスの関係は、必ずこちらが与えるものをそのまま使用してください。 +- 英文中のすべての文の要素や構成単位に対して、範囲(文の主要素、修飾語、句(ここでは準動詞句のみを指す)、節)を必ず作成してください。 +- 並列構造の場合には、並列構造全体ではなく必ずそれぞれの子要素に対して範囲を作成してください。 +- 句や節の入れ子の中の文の要素や構成単位に対しては、必ず範囲を作成してください。 +- すべての範囲に対して、文の主要素にはS、V、O、Cのいずれかを、修飾語にはMを、句と節にはS、O、C、Mのいずれかを必ず割り当ててください。 +- 句(ここでは準動詞句のみを指す)や節が他の名詞や名詞句を修飾している場合には、句や節から被修飾語句に向かう関係をすべて必ず作成してください。 +- これらの関係以外には、関係を作成しないでください。 +- 関係を作成する際に始点あるいは終点となる範囲が文の要素や構成単位でない場合に限り、範囲(関係)を作成することができます。それ以外の場合には、範囲(関係)を作成しないでください。 +- 等位接続詞や相関接続詞による並列構造がある場合には、すべての並列構造を必ず作成してください。 +- 並列構造を作成する際には、内部のすべての子要素に対して子要素(等位接続詞、相関接続詞、並列要素)を必ず作成してください。 +- 子要素の範囲の開始と終了を表す単語のインデックスは、隣の子要素のインデックスと完全に連続している必要があります。`; + +const examplePrompt = examples + .map((example, index) => { + const { + text: _exampleText, + words: _exampleWords, + ..._exampleAnnotationData + } = example; + const exampleText = _exampleText; + const exampleWords = _exampleWords + .map((word) => `${word.text}:${word.index}`) + .join("\n "); + const exampleAnnotationData = JSON.stringify( + SimplifiedAnnotationDataSchema.parse( + _exampleAnnotationData satisfies SimplifiedAnnotationData, + ), + null, + 2, + ); + return `\ +## 例${index + 1} +英文:${exampleText} +単語とそれに対応するインデックスの関係: + ${exampleWords} +JSON: +${exampleAnnotationData}`; + }) + .join("\n\n"); + +export function generateGeminiPrompt(text: string, words: string[]): Prompt { + const prompt = { + systemInstruction: `\ +${instructionText} + +## JSON Schema +${JSON.stringify(z.toJSONSchema(SimplifiedAnnotationDataSchema), null, 2)} + +${examplePrompt}`, + userInput: `\ +英文:${text} +単語とそれに対応するインデックスの関係: + ${words.map((word, index) => `${word}:${index}`).join("\n ")}`, + }; + return prompt; +} + +export function generateGPTPrompt(text: string, words: string[]): Prompt { + const prompt = { + systemInstruction: `\ +${instructionText} + +${examplePrompt}`, + userInput: `\ +英文:${text} +単語とそれに対応するインデックスの関係: + ${words.map((word, index) => `${word}:${index}`).join("\n ")}`, + }; + return prompt; +} + +// export function generateLlamaPrompt(text: string, words: string[]) { +// const prompt: [ +// { +// role: "system"; +// content: string; +// }, +// { +// role: "user"; +// content: string; +// }, +// ] = [ +// { +// role: "system" as const, +// content: `\ +// ${instructionText} + +// ## JSON Schema +// ${JSON.stringify(z.toJSONSchema(SimplifiedAnnotationDataSchema), null, 2)} + +// ${examplePrompt}`, +// }, +// { +// role: "user" as const, +// content: `\ +// 英文:${text} +// 単語とそれに対応するインデックスの関係: +// ${words.map((word, index) => `${word}:${index}`).join("\n ")}`, +// }, +// ]; +// return prompt; +// } diff --git a/packages/evaluation/show-differences-by-json-patch.ts b/packages/evaluation/show-differences-by-json-patch.ts new file mode 100644 index 0000000..6068df7 --- /dev/null +++ b/packages/evaluation/show-differences-by-json-patch.ts @@ -0,0 +1,40 @@ +// import { readFileSync } from "node:fs"; +// import jsonpatch from "fast-json-patch"; +// import { type SimplifiedSentenceStructureData } from "@sentence-structure-diagram-app/sentence-structure-data"; +// import type { Dataset, ModelName } from "./types.js"; + +// const modelName: ModelName = "gpt-5.1"; + +// const datasets: Dataset[] = JSON.parse( +// readFileSync(`${import.meta.dirname}/data/datasets.json`, "utf-8"), +// ); + +// let differenceCount = 0; +// for (const dataset of datasets) { +// const answerSimplifiedSentenceStructureData: SimplifiedSentenceStructureData = +// JSON.parse( +// readFileSync( +// `${import.meta.dirname}/output/answer-${dataset.id}.json`, +// "utf-8", +// ), +// ); +// const llmSimplifiedSentenceStructureData: SimplifiedSentenceStructureData = +// JSON.parse( +// readFileSync( +// `${import.meta.dirname}/output/${modelName}-${dataset.id}.json`, +// "utf-8", +// ), +// ); + +// const differences = jsonpatch.compare( +// answerSimplifiedSentenceStructureData, +// llmSimplifiedSentenceStructureData, +// ); +// differenceCount += differences.length; +// console.log( +// `Number of differences between answer and ${modelName} for dataset ID ${dataset.id}: ${differences.length}`, +// ); +// } +// console.log( +// `Total number of differences between answer and ${modelName}: ${differenceCount}`, +// ); diff --git a/packages/evaluation/tsconfig.json b/packages/evaluation/tsconfig.json new file mode 100644 index 0000000..d6a2b39 --- /dev/null +++ b/packages/evaluation/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/packages/frontend/.env b/packages/frontend/.env new file mode 100644 index 0000000..b3d1a5c --- /dev/null +++ b/packages/frontend/.env @@ -0,0 +1 @@ +VITE_API_ENDPOINT=http://localhost:3000 diff --git a/packages/frontend/.gitignore b/packages/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/packages/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/eslint.config.js b/packages/frontend/eslint.config.js similarity index 56% rename from eslint.config.js rename to packages/frontend/eslint.config.js index e221991..75d3c46 100644 --- a/eslint.config.js +++ b/packages/frontend/eslint.config.js @@ -1,9 +1,7 @@ import js from "@eslint/js"; import globals from "globals"; -import reactDom from "eslint-plugin-react-dom"; import reactHooks from "eslint-plugin-react-hooks"; import reactRefresh from "eslint-plugin-react-refresh"; -import reactX from "eslint-plugin-react-x"; import tseslint from "typescript-eslint"; import { defineConfig, globalIgnores } from "eslint/config"; @@ -13,19 +11,13 @@ export default defineConfig([ files: ["**/*.{ts,tsx}"], extends: [ js.configs.recommended, - tseslint.configs.recommendedTypeChecked, - reactDom.configs.recommended, - reactHooks.configs["recommended-latest"], + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, reactRefresh.configs.vite, - reactX.configs["recommended-typescript"], ], languageOptions: { ecmaVersion: 2020, globals: globals.browser, - parserOptions: { - project: ["./tsconfig.node.json", "./tsconfig.app.json"], - tsconfigRootDir: import.meta.dirname, - }, }, }, ]); diff --git a/index.html b/packages/frontend/index.html similarity index 81% rename from index.html rename to packages/frontend/index.html index 0661e71..cf3c3e1 100644 --- a/index.html +++ b/packages/frontend/index.html @@ -4,7 +4,7 @@ - sentence-structure-diagram-app + 英文構造図作図支援アプリ(ベータ版)
diff --git a/packages/frontend/package.json b/packages/frontend/package.json new file mode 100644 index 0000000..d8f1750 --- /dev/null +++ b/packages/frontend/package.json @@ -0,0 +1,42 @@ +{ + "name": "@sentence-structure-diagram-app/frontend", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview", + "clean": "rm -r dist" + }, + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/icons-material": "^7.3.6", + "@mui/material": "^7.3.6", + "@sentence-structure-diagram-app/backend": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-svg": "^0.1.0", + "@tanstack/react-query": "^5.90.12", + "@trpc/client": "^11.7.2", + "@trpc/tanstack-react-query": "^11.7.2", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/node": "^24.10.1", + "@types/react": "^19.2.5", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.4", + "vite": "^7.2.4" + } +} diff --git a/public/vite.svg b/packages/frontend/public/vite.svg similarity index 100% rename from public/vite.svg rename to packages/frontend/public/vite.svg diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx new file mode 100644 index 0000000..23f2800 --- /dev/null +++ b/packages/frontend/src/App.tsx @@ -0,0 +1,11 @@ +import { QueryClientProvider } from "@tanstack/react-query"; +import { queryClient } from "./utils/trpc"; +import Home from "./pages"; + +export default function App() { + return ( + + + + ); +} diff --git a/packages/frontend/src/main.tsx b/packages/frontend/src/main.tsx new file mode 100644 index 0000000..5d4a2be --- /dev/null +++ b/packages/frontend/src/main.tsx @@ -0,0 +1,9 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import App from "./App.tsx"; + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/packages/frontend/src/pages/components/AppBar.tsx b/packages/frontend/src/pages/components/AppBar.tsx new file mode 100644 index 0000000..9b84587 --- /dev/null +++ b/packages/frontend/src/pages/components/AppBar.tsx @@ -0,0 +1,148 @@ +import { useRef, useState } from "react"; +import { + AppBar as MUIAppBar, + IconButton, + ListItemIcon, + Menu, + MenuItem, + Toolbar, + Typography, +} from "@mui/material"; +import { + FileDownload as FileDownloadIcon, + FileUpload as FileUploadIcon, + Menu as MenuIcon, +} from "@mui/icons-material"; +import { + createSentenceStructureDataFromStringData, + createSentenceStructureDataFromXMLData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import { xmlStringToConfigurations } from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; +import { useSentenceStructureData } from "../contexts/SentenceStructureDataProvider"; +import { useConfigurations } from "../contexts/ConfigurationsProvider"; +import ExportDialog from "./ExportDialog"; + +export default function AppBar() { + const [anchorElement, setAnchorElement] = useState(null); + + const [isExportDialogOpen, setIsExportDialogOpen] = useState(false); + + const fileInputRef = useRef(null); + + const { setSentenceStructureData } = useSentenceStructureData(); + + const { setConfigurations } = useConfigurations(); + + return ( + + + + 英文構造図作図支援アプリ(ベータ版) + + setAnchorElement(e.currentTarget)}> + + + setAnchorElement(null)} + > + { + setAnchorElement(null); + setIsExportDialogOpen(true); + }} + > + + + + エクスポート + + { + setAnchorElement(null); + fileInputRef.current?.click(); + }} + > + + + + インポート + + + setIsExportDialogOpen(false)} + /> + { + const file = e.target.files?.[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = () => { + try { + if (typeof reader.result !== "string") + throw new Error("Invalid file"); + if (file.name.endsWith(".json")) { + const result = createSentenceStructureDataFromStringData( + reader.result, + ); + if (result.success) { + setSentenceStructureData( + result.data.newSentenceStructureData, + ); + } else { + alert(result.message); + } + } else { + const svg = new DOMParser().parseFromString( + reader.result, + "image/svg+xml", + ); + const sentenceStructureDataResult = + createSentenceStructureDataFromXMLData( + svg.querySelector("sentence-structure-data")?.innerHTML ?? + "", + ); + if (sentenceStructureDataResult.success) { + setSentenceStructureData( + sentenceStructureDataResult.data.newSentenceStructureData, + ); + } else { + alert(sentenceStructureDataResult.message); + return; + } + // const newSentenceStructure = + // simplifiedSentenceStructureDataToSentenceStructureData.decode( + // stringToSimplifiedSentenceStructureData.decode( + // svg.getElementById("sentence-structure-data") + // ?.textContent ?? "", + // ), + // ); + + setConfigurations( + xmlStringToConfigurations.decode( + svg.querySelector("configurations")?.innerHTML ?? "", + ), + ); + // const newConfigurations = stringToConfigurations.decode( + // svg.getElementById("configurations")?.textContent ?? "", + // ); + } + } catch { + alert( + "ファイルの読み込みに失敗しました。正しい形式のファイルを選択してください。", + ); + } + }; + reader.readAsText(file); + }} + /> + + + ); +} diff --git a/packages/frontend/src/pages/components/ConfirmClearAllDialog.tsx b/packages/frontend/src/pages/components/ConfirmClearAllDialog.tsx new file mode 100644 index 0000000..ff1291d --- /dev/null +++ b/packages/frontend/src/pages/components/ConfirmClearAllDialog.tsx @@ -0,0 +1,44 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, +} from "@mui/material"; +import { useSentenceStructureData } from "../contexts/SentenceStructureDataProvider"; + +type ConfirmClearAllDialogProps = { + isOpen: boolean; + onClose: () => void; +}; + +export default function ConfirmClearAllDialog({ + isOpen, + onClose, +}: ConfirmClearAllDialogProps) { + const { initialSentenceStructureData, setSentenceStructureData } = + useSentenceStructureData(); + + return ( + + 本当に全てクリアしますか? + + + 全てクリアすると、入力した英文と注釈データがすべて失われます。この操作は元に戻せません。 + + + + + + + + ); +} diff --git a/packages/frontend/src/pages/components/ConfirmClearAnnotationsDialog.tsx b/packages/frontend/src/pages/components/ConfirmClearAnnotationsDialog.tsx new file mode 100644 index 0000000..2dc269a --- /dev/null +++ b/packages/frontend/src/pages/components/ConfirmClearAnnotationsDialog.tsx @@ -0,0 +1,35 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, +} from "@mui/material"; + +type ConfirmClearAnnotationsDialogProps = { + isOpen: boolean; + onClose: () => void; + onConfirm: () => void; +}; + +export default function ConfirmClearAnnotationsDialog({ + isOpen, + onClose, + onConfirm, +}: ConfirmClearAnnotationsDialogProps) { + return ( + + 本当にテキスト編集モードに切り替えますか? + + + テキスト編集モードに切り替えると、現在の注釈データがすべて失われます。この操作は元に戻せません。 + + + + + + + + ); +} diff --git a/packages/frontend/src/pages/components/ExportDialog.tsx b/packages/frontend/src/pages/components/ExportDialog.tsx new file mode 100644 index 0000000..713c452 --- /dev/null +++ b/packages/frontend/src/pages/components/ExportDialog.tsx @@ -0,0 +1,494 @@ +import { useState } from "react"; +import { + AppBar, + Box, + Button, + Dialog, + Divider, + FormControl, + IconButton, + Input, + InputLabel, + MenuItem, + Paper, + Select, + Slider, + Stack, + TextField, + Toolbar, + Typography, +} from "@mui/material"; +import { Close as CloseIcon } from "@mui/icons-material"; +import { sentenceStructureDataToString } from "@sentence-structure-diagram-app/sentence-structure-data"; +import { generateSvgString } from "@sentence-structure-diagram-app/sentence-structure-diagram-svg"; +import { useSentenceStructureData } from "../contexts/SentenceStructureDataProvider"; +import { useConfigurations } from "../contexts/ConfigurationsProvider"; +import { measureTextWidth } from "../utils/measure-text-width"; + +type ExportDialogProps = { + isOpen: boolean; + onClose: () => void; +}; + +export default function ExportDialog({ isOpen, onClose }: ExportDialogProps) { + const [imageWidth, setImageWidth] = useState(1000); + + const { sentenceStructureData } = useSentenceStructureData(); + const { configurations, setConfigurations } = useConfigurations(); + + return ( + + + + + + + + + エクスポート + + + + + + + + + + + + + + + 画像の幅 + + + setImageWidth(newValue)} + min={500} + max={1500} + valueLabelDisplay="auto" + /> + setImageWidth(Number(e.target.value))} + inputProps={{ + step: 100, + min: 500, + max: 1500, + type: "number", + }} + /> + + + + + + 色 + + + + setConfigurations({ + ...configurations, + color: { + ...configurations.color, + primaryColor: e.target.value, + }, + }) + } + sx={{ minWidth: 140 }} + /> + + setConfigurations({ + ...configurations, + color: { + ...configurations.color, + textColor: e.target.value, + }, + }) + } + sx={{ minWidth: 140 }} + /> + + + + + + 文の構成単位の範囲 + + + + 修飾語 + + + + + + + + + + + + + + + + 文の要素 + + + + setConfigurations({ + ...configurations, + sentenceElementNameToSentenceElementSymbolMap: { + ...configurations.sentenceElementNameToSentenceElementSymbolMap, + S: e.target.value, + }, + }) + } + /> + + setConfigurations({ + ...configurations, + sentenceElementNameToSentenceElementSymbolMap: { + ...configurations.sentenceElementNameToSentenceElementSymbolMap, + V: e.target.value, + }, + }) + } + /> + + setConfigurations({ + ...configurations, + sentenceElementNameToSentenceElementSymbolMap: { + ...configurations.sentenceElementNameToSentenceElementSymbolMap, + C: e.target.value, + }, + }) + } + /> + + setConfigurations({ + ...configurations, + sentenceElementNameToSentenceElementSymbolMap: { + ...configurations.sentenceElementNameToSentenceElementSymbolMap, + O: e.target.value, + }, + }) + } + /> + + setConfigurations({ + ...configurations, + sentenceElementNameToSentenceElementSymbolMap: { + ...configurations.sentenceElementNameToSentenceElementSymbolMap, + M: e.target.value, + }, + }) + } + /> + + + + + + 矢印の形状 + + + + 矢印の形状 + + + + + + + + レイアウト方式 + + + + レイアウト方式 + + + + + + + + ); +} diff --git a/packages/frontend/src/pages/components/SentenceStructureDiagramAnnotator.tsx b/packages/frontend/src/pages/components/SentenceStructureDiagramAnnotator.tsx new file mode 100644 index 0000000..4deef84 --- /dev/null +++ b/packages/frontend/src/pages/components/SentenceStructureDiagramAnnotator.tsx @@ -0,0 +1,296 @@ +import { Fragment } from "react/jsx-runtime"; +import { alpha, useTheme } from "@mui/material"; +import { + findCoordinationById, + findRangeById, + findRelationById, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import type { SentenceStructureDiagramData } from "@sentence-structure-diagram-app/sentence-structure-diagram-data"; +import { useSentenceStructureData } from "../contexts/SentenceStructureDataProvider"; +import { useInteractionState } from "../contexts/InteractionStateProvider"; + +type SentenceStructureDiagramAnnotatorProps = { + sentenceStructureDiagramData: SentenceStructureDiagramData; +}; + +export default function SentenceStructureDiagramAnnotator( + props: SentenceStructureDiagramAnnotatorProps, +) { + const theme = useTheme(); + + const { sentenceStructureData } = useSentenceStructureData(); + + const { + interactionState, + handleMouseUpOnWord, + handleMouseEnterOnWord, + handleMouseDownOnWord, + handleClickOnRange, + handleClickOnRelation, + handleClickOnCoordination, + } = useInteractionState(); + + return ( + + {/* 単語と括弧類 */} + {props.sentenceStructureDiagramData.words.map((word) => { + const isWithinSelectingRange = + (interactionState.type === "range-selecting" || + interactionState.type === "relation-selecting" || + interactionState.type === "coordination-selecting") && + Math.min( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ) <= word.index && + word.index <= + Math.max( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ); + const isWithinConfirmingRange = + (interactionState.type === "range-confirming" || + interactionState.type === "coordination-confirming") && + interactionState.startWordIndex <= word.index && + word.index <= interactionState.endWordIndex; + const isWithinSelectedCoordinationChild = (() => { + if ( + !( + interactionState.type === "coordination-idle" || + interactionState.type === "coordination-selecting" || + interactionState.type === "coordination-confirming" + ) + ) + return false; + return interactionState.children.some( + (child) => + child.startWordIndex <= word.index && + word.index <= child.endWordIndex, + ); + })(); + const isWithinSelectedRange = (() => { + if ( + !( + interactionState.type === "range-selected" || + interactionState.type === "relation-idle" || + interactionState.type === "relation-selecting" + ) + ) + return false; + const range = + interactionState.type === "range-selected" + ? findRangeById(sentenceStructureData, { + rangeId: interactionState.rangeId, + }) + : interactionState.fromRange; + return ( + range !== null && + range.startWordIndex <= word.index && + word.index <= range.endWordIndex + ); + })(); + const isWithinSelectedRelationRange = (() => { + if (interactionState.type !== "relation-selected") return false; + const relation = findRelationById(sentenceStructureData, { + relationId: interactionState.relationId, + }); + if (relation === null) return false; + const fromRange = findRangeById(sentenceStructureData, { + rangeId: relation.fromRangeId, + }); + const toRange = findRangeById(sentenceStructureData, { + rangeId: relation.toRangeId, + }); + if (fromRange === null || toRange === null) return false; + return ( + (fromRange.startWordIndex <= word.index && + word.index <= fromRange.endWordIndex) || + (toRange.startWordIndex <= word.index && + word.index <= toRange.endWordIndex) + ); + })(); + const isWithinSelectedCoordination = (() => { + if (interactionState.type !== "coordination-selected") return false; + const coordination = findCoordinationById(sentenceStructureData, { + coordinationId: interactionState.coordinationId, + }); + if (coordination === null) return false; + return coordination.children.some( + (child) => + child.startWordIndex <= word.index && + word.index <= child.endWordIndex, + ); + })(); + const isSelecting = isWithinSelectingRange || isWithinConfirmingRange; + const isSelected = + isWithinSelectedCoordinationChild || + isWithinSelectedRange || + isWithinSelectedRelationRange || + isWithinSelectedCoordination; + + return ( + + {word.openingBrackets.length > 0 && ( + + {word.openingBrackets.join("")} + + )} + { + const result = handleMouseDownOnWord(word.index); + if (!result.success) { + alert(result.message); + } + }} + onMouseEnter={(e) => { + if (e.buttons !== 1) return; + const result = handleMouseEnterOnWord(word.index); + if (!result.success) { + alert(result.message); + } + }} + onMouseUp={(e) => { + e.stopPropagation(); + const result = handleMouseUpOnWord(word.index); + if (!result.success) { + alert(result.message); + } + }} + > + + + {word.text} + + + {word.closingBrackets.length > 0 && ( + + {word.closingBrackets.join("")} + + )} + + ); + })} + {/* 下線 */} + {props.sentenceStructureDiagramData.underlines.map((underline) => + underline.position.map((position, index) => ( + + )), + )} + {/* 文の要素の記号 */} + {props.sentenceStructureDiagramData.sentenceElements.map( + (sentenceElement) => + sentenceElement.symbol && ( + { + const result = handleClickOnRange(sentenceElement.rangeId); + if (!result.success) { + alert(result.message); + } + }} + > + {sentenceElement.symbol} + + ), + )} + {/* 矢印 */} + {props.sentenceStructureDiagramData.relations.map((relation) => ( + { + const result = handleClickOnRelation(relation.relationId); + if (!result.success) { + alert(result.message); + } + }} + /> + ))} + {/* 並列 */} + {props.sentenceStructureDiagramData.coordinations.map((coordination) => ( + { + const result = handleClickOnCoordination( + coordination.coordinationId, + ); + if (!result.success) { + alert(result.message); + } + }} + /> + ))} + + ); +} diff --git a/packages/frontend/src/pages/components/SentenceStructureEditor.tsx b/packages/frontend/src/pages/components/SentenceStructureEditor.tsx new file mode 100644 index 0000000..56ebb02 --- /dev/null +++ b/packages/frontend/src/pages/components/SentenceStructureEditor.tsx @@ -0,0 +1,642 @@ +import { useEffect, useRef, useState } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { trpc } from "../../utils/trpc"; +import { + Box, + Button, + Divider, + Paper, + TextField, + ToggleButton, + ToggleButtonGroup, + Tooltip, +} from "@mui/material"; +import { + AutoAwesome as AutoAwesomeIcon, + ClearAll as ClearAllIcon, + EditNote as EditNoteIcon, + Schema as SchemaIcon, +} from "@mui/icons-material"; +import { + coordinationChildTypeOptions, + createSentenceStructureDataFromSimplifiedAnnotationData, + createSentenceStructureDataFromText, + findCoordinationById, + findRangeById, + findRelationById, + sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap, + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap, + type CoordinationChildType, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import { convertSentenceStructureDataToSentenceStructureDiagramData } from "@sentence-structure-diagram-app/sentence-structure-diagram-data"; +import { useSentenceStructureData } from "../contexts/SentenceStructureDataProvider"; +import { useInteractionState } from "../contexts/InteractionStateProvider"; +import { measureTextWidth } from "../utils/measure-text-width"; +import AppBar from "./AppBar"; +import ConfirmClearAnnotationsDialog from "./ConfirmClearAnnotationsDialog"; +import ConfirmClearAllDialog from "./ConfirmClearAllDialog"; +import SentenceStructureDiagramAnnotator from "./SentenceStructureDiagramAnnotator"; + +type ViewMode = "edit" | "annotate"; + +export default function SentenceStructureEditor() { + const [viewMode, _setViewMode] = useState(() => { + const savedViewMode = localStorage.getItem("viewMode"); + if (savedViewMode === "annotate") return "annotate"; + return "edit"; + }); + function setViewMode(newViewMode: ViewMode) { + localStorage.setItem("viewMode", newViewMode); + _setViewMode(newViewMode); + } + const [ + isConfirmClearAnnotationsDialogOpen, + setIsConfirmClearAnnotationsDialogOpen, + ] = useState(false); + const [isConfirmClearAllDialogOpen, setIsConfirmClearAllDialogOpen] = + useState(false); + + const { data: statusData } = useQuery(trpc.status.queryOptions()); + const generateSentenceStructureMutation = useMutation( + trpc.generateSentenceStructure.mutationOptions(), + ); + + const { sentenceStructureData, setSentenceStructureData } = + useSentenceStructureData(); + + const { + interactionState, + handleMouseUpOutsideWord, + handleCreateSentenceElementRange, + handleCreateSentenceStructureRange, + handleUpdateSentenceElementName, + handleDeleteRange, + handleStartCreatingRelation, + handleCancelCreatingRelation, + handleDeleteRelation, + handleStartCreatingCoordination, + handleCreateCoordinationChild, + handleConfirmCreatingCoordination, + handleCancelCreatingCoordination, + handleDeleteCoordination, + } = useInteractionState(); + useEffect(() => { + function onMouseUp() { + const result = handleMouseUpOutsideWord(); + if (!result.success) { + alert(result.message); + } + } + document.addEventListener("mouseup", onMouseUp); + return () => { + document.removeEventListener("mouseup", onMouseUp); + }; + }, [handleMouseUpOutsideWord]); + + const canvasRef = useRef(null); + const [maxWidth, setMaxWidth] = useState(1000); + useEffect(() => { + if (!canvasRef.current) return; + const resizeObserver = new ResizeObserver(() => { + setMaxWidth(canvasRef.current?.getBoundingClientRect().width ?? 0); + }); + resizeObserver.observe(canvasRef.current); + + return () => resizeObserver.disconnect(); + }, [canvasRef, setMaxWidth, viewMode]); + + const sentenceStructureDiagramData = + convertSentenceStructureDataToSentenceStructureDiagramData( + sentenceStructureData, + maxWidth, + measureTextWidth, + { + layoutMode: "linear", + }, + ); + + return ( + <> + + + + + { + if ( + newValue === "edit" && + (sentenceStructureData.ranges.length !== 0 || + sentenceStructureData.relations.length !== 0 || + sentenceStructureData.coordinations.length !== 0) + ) { + setIsConfirmClearAnnotationsDialogOpen(true); + return; + } + setViewMode(newValue); + }} + sx={{ flex: 1 }} + > + + + + + + + + + + + + setIsConfirmClearAnnotationsDialogOpen(false)} + onConfirm={() => { + setIsConfirmClearAnnotationsDialogOpen(false); + setViewMode("edit"); + }} + /> + + + + setIsConfirmClearAllDialogOpen(false)} + /> + + + {viewMode === "edit" ? ( + { + setSentenceStructureData( + createSentenceStructureDataFromText({ text: e.target.value }), + ); + }} + placeholder="ここに英文を入力してください。" + /> + ) : ( + + + + + + {/* 範囲の作成 */} + {interactionState.type === "range-confirming" && + (() => { + const endWord = + sentenceStructureDiagramData.words[ + interactionState.endWordIndex + ]; + return ( + e.stopPropagation()} + sx={{ + position: "absolute", + left: + (endWord.position.left + endWord.position.right) / 2, + top: endWord.position.top - 8, + translate: "-50% -100%", + display: "flex", + whiteSpace: "nowrap", + }} + > + + + + + + + + + + + ); + })()} + + {/* 文の要素の付与 */} + {interactionState.type === "range-selected" && + (() => { + const activeRange = findRangeById(sentenceStructureData, { + rangeId: interactionState.rangeId, + }); + if (activeRange === null) + throw new Error("Active range not found"); + const endWord = + sentenceStructureDiagramData.words[ + activeRange.endWordIndex + ]; + return ( + e.stopPropagation()} + > + {(activeRange.kind === "sentence-element" + ? sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap[ + activeRange.type + ] + : activeRange.kind === "sentence-structure" + ? sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap[ + activeRange.type + ] + : null + )?.map((allowedSentenceElement) => ( + + ))} + + + + + + + + ); + })()} + + {/* 矢印の作成のキャンセル */} + {(interactionState.type === "relation-idle" || + interactionState.type === "relation-selecting") && + (() => { + const endWord = + sentenceStructureDiagramData.words[ + interactionState.fromRange.endWordIndex + ]; + return ( + e.stopPropagation()} + sx={{ + position: "absolute", + left: + (endWord.position.left + endWord.position.right) / 2, + top: endWord.position.top - 8, + translate: "-50% -100%", + display: "flex", + whiteSpace: "nowrap", + }} + > + + + ); + })()} + + {/* 矢印の削除 */} + {interactionState.type === "relation-selected" && + (() => { + const activeRelation = findRelationById( + sentenceStructureData, + { + relationId: interactionState.relationId, + }, + ); + if (activeRelation === null) + throw new Error("Active relation not found"); + const fromRange = findRangeById(sentenceStructureData, { + rangeId: activeRelation.fromRangeId, + }); + if (fromRange === null) + throw new Error("From range not found"); + const endWord = + sentenceStructureDiagramData.words[fromRange.endWordIndex]; + return ( + e.stopPropagation()} + sx={{ + position: "absolute", + left: + (endWord.position.left + endWord.position.right) / 2, + top: endWord.position.top - 8, + translate: "-50% -100%", + display: "flex", + whiteSpace: "nowrap", + }} + > + + + ); + })()} + + {/* 並列の要素の作成 */} + {interactionState.type === "coordination-confirming" && + (() => { + const endWord = + sentenceStructureDiagramData.words[ + interactionState.endWordIndex + ]; + return ( + e.stopPropagation()} + sx={{ + position: "absolute", + left: + (endWord.position.left + endWord.position.right) / 2, + top: endWord.position.top - 8, + translate: "-50% -100%", + display: "flex", + whiteSpace: "nowrap", + }} + > + {coordinationChildTypeOptions.map( + (coordinationChildType) => ( + + ), + )} + + ); + })()} + + {/* 並列の作成のキャンセル */} + {(interactionState.type === "coordination-idle" || + interactionState.type === "coordination-selecting") && + (() => { + const endWord = + sentenceStructureDiagramData.words[ + interactionState.children[0].endWordIndex + ]; + return ( + e.stopPropagation()} + sx={{ + position: "absolute", + left: + (endWord.position.left + endWord.position.right) / 2, + top: endWord.position.top - 8, + translate: "-50% -100%", + display: "flex", + whiteSpace: "nowrap", + }} + > + + + + + ); + })()} + + {/* 並列の削除 */} + {interactionState.type === "coordination-selected" && + (() => { + const activeCoordination = findCoordinationById( + sentenceStructureData, + { + coordinationId: interactionState.coordinationId, + }, + ); + if (activeCoordination === null) + throw new Error("Active coordination not found"); + const endChild = activeCoordination.children.at(-1); + if (endChild == null) throw new Error("End child not found"); + const endWord = + sentenceStructureDiagramData.words[endChild.endWordIndex]; + return ( + e.stopPropagation()} + sx={{ + position: "absolute", + left: + (endWord.position.left + endWord.position.right) / 2, + top: endWord.position.top - 8, + translate: "-50% -100%", + display: "flex", + whiteSpace: "nowrap", + }} + > + + + ); + })()} + + )} + + + + ); +} diff --git a/packages/frontend/src/pages/contexts/ConfigurationsProvider.tsx b/packages/frontend/src/pages/contexts/ConfigurationsProvider.tsx new file mode 100644 index 0000000..07c7bd6 --- /dev/null +++ b/packages/frontend/src/pages/contexts/ConfigurationsProvider.tsx @@ -0,0 +1,72 @@ +import { + createContext, + useContext, + useState, + type PropsWithChildren, +} from "react"; +import { + defaultConfigurations, + stringToConfigurations, + xmlStringToConfigurations, + type Configurations, +} from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; + +type ConfigurationsContextValue = { + configurations: Configurations; + setConfigurations: (newConfigurations: Configurations) => void; + setConfigurationsFromXMLData: (xmlString: string) => void; +}; + +const ConfigurationsContext = createContext( + null, +); + +export function ConfigurationsProvider(props: PropsWithChildren) { + const [configurations, _setConfigurations] = useState(() => { + const savedConfigurations = localStorage.getItem("configurations"); + if (!savedConfigurations) { + return defaultConfigurations; + } + const result = stringToConfigurations.safeDecode(savedConfigurations); + if (result.success) { + return result.data; + } else { + return defaultConfigurations; + } + }); + + function setConfigurations(newConfigurations: Configurations) { + const result = stringToConfigurations.safeEncode(newConfigurations); + if (result.success) { + localStorage.setItem("configurations", result.data); + } + _setConfigurations(newConfigurations); + } + + function setConfigurationsFromXMLData(xmlString: string) { + setConfigurations(xmlStringToConfigurations.decode(xmlString)); + } + + return ( + + {props.children} + + ); +} + +// eslint-disable-next-line react-refresh/only-export-components +export function useConfigurations() { + const context = useContext(ConfigurationsContext); + if (!context) { + throw new Error( + "useConfigurations must be used within a ConfigurationsProvider", + ); + } + return context; +} diff --git a/packages/frontend/src/pages/contexts/InteractionStateProvider.tsx b/packages/frontend/src/pages/contexts/InteractionStateProvider.tsx new file mode 100644 index 0000000..e4b8051 --- /dev/null +++ b/packages/frontend/src/pages/contexts/InteractionStateProvider.tsx @@ -0,0 +1,1229 @@ +import { + createContext, + useContext, + useState, + type PropsWithChildren, +} from "react"; +import { + createCoordination, + createRelation, + createSentenceElementRange, + createSentenceStructureRange, + deleteCoordination, + deleteRange, + deleteRelation, + findRangeById, + findRangeByStartAndEndWordIndex, + updateSentenceElementName, + type CoordinationChildType, + type RangeType, + type SentenceElementName, + type SentenceElementRangeType, + type SentenceStructureData, + type SentenceStructureRangeType, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import { useSentenceStructureData } from "./SentenceStructureDataProvider"; + +type InteractionState = + | { + type: "idle"; + } + | { + type: "range-selecting"; + anchorWordIndex: number; + focusWordIndex: number; + } + | { + type: "range-confirming"; + startWordIndex: number; + endWordIndex: number; + } + | { + type: "range-selected"; + rangeType: RangeType; + rangeId: string; + } + | { + type: "relation-idle"; + fromRange: { + startWordIndex: number; + endWordIndex: number; + }; + } + | { + type: "relation-selecting"; + fromRange: { + startWordIndex: number; + endWordIndex: number; + }; + anchorWordIndex: number; + focusWordIndex: number; + } + | { + type: "relation-selected"; + relationId: string; + } + | { + type: "coordination-idle"; + children: { + type: CoordinationChildType; + startWordIndex: number; + endWordIndex: number; + }[]; + } + | { + type: "coordination-selecting"; + children: { + type: CoordinationChildType; + startWordIndex: number; + endWordIndex: number; + }[]; + anchorWordIndex: number; + focusWordIndex: number; + } + | { + type: "coordination-confirming"; + children: { + type: CoordinationChildType; + startWordIndex: number; + endWordIndex: number; + }[]; + startWordIndex: number; + endWordIndex: number; + } + | { + type: "coordination-selected"; + coordinationId: string; + }; + +type InteractionStateAction = + | { + type: "MOUSE_UP_OUTSIDE_WORD"; + } + | { + type: "MOUSE_DOWN_ON_WORD"; + payload: { + wordIndex: number; + }; + } + | { + type: "MOUSE_ENTER_ON_WORD"; + payload: { + wordIndex: number; + }; + } + | { + type: "MOUSE_UP_ON_WORD"; + payload: { + wordIndex: number; + }; + } + | { + type: "CREATE_SENTENCE_ELEMENT_RANGE"; + payload: { + rangeType: SentenceElementRangeType; + }; + } + | { + type: "CREATE_SENTENCE_STRUCTURE_RANGE"; + payload: { + rangeType: SentenceStructureRangeType; + }; + } + | { + type: "CLICK_ON_RANGE"; + payload: { + rangeId: string; + }; + } + | { + type: "UPDATE_SENTENCE_ELEMENT_NAME"; + payload: { + sentenceElementName: SentenceElementName; + }; + } + | { + type: "DELETE_RANGE"; + } + | { + type: "START_CREATING_RELATION"; + } + | { + type: "CANCEL_CREATING_RELATION"; + } + | { + type: "CLICK_ON_RELATION"; + payload: { + relationId: string; + }; + } + | { + type: "DELETE_RELATION"; + } + | { + type: "START_CREATING_COORDINATION"; + } + | { + type: "CREATE_COORDINATION_CHILD"; + payload: { + coordinationChildType: CoordinationChildType; + }; + } + | { + type: "CONFIRM_CREATING_COORDINATION"; + } + | { + type: "CANCEL_CREATING_COORDINATION"; + } + | { + type: "CLICK_ON_COORDINATION"; + payload: { + coordinationId: string; + }; + } + | { + type: "DELETE_COORDINATION"; + }; + +function interactionStateReducer( + interactionState: InteractionState, + sentenceStructureData: SentenceStructureData, + action: InteractionStateAction, +): + | { + success: true; + interactionState: InteractionState; + sentenceStructureData: SentenceStructureData; + } + | { + success: false; + message: string; + } { + switch (action.type) { + case "MOUSE_UP_OUTSIDE_WORD": + switch (interactionState.type) { + case "idle": + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData, + }; + case "range-selecting": { + const matchedRange = findRangeByStartAndEndWordIndex( + sentenceStructureData, + { + startWordIndex: Math.min( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ), + endWordIndex: Math.max( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ), + }, + ); + if (matchedRange) { + return { + success: true, + interactionState: { + type: "range-selected", + rangeType: matchedRange.type, + rangeId: matchedRange.id, + }, + sentenceStructureData, + }; + } else { + return { + success: true, + interactionState: { + type: "range-confirming", + startWordIndex: Math.min( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ), + endWordIndex: Math.max( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ), + }, + sentenceStructureData, + }; + } + } + case "range-confirming": + case "range-selected": + case "relation-idle": + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData, + }; + case "relation-selecting": { + const newSentenceStructureData = createRelation( + sentenceStructureData, + { + fromRange: interactionState.fromRange, + toRange: { + startWordIndex: Math.min( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ), + endWordIndex: Math.max( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ), + }, + }, + ); + if (newSentenceStructureData.success) { + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData: + newSentenceStructureData.data.newSentenceStructureData, + }; + } else { + return { + success: false, + message: newSentenceStructureData.message, + }; + } + } + case "relation-selected": + case "coordination-idle": + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData, + }; + case "coordination-selecting": { + return { + success: true, + interactionState: { + type: "coordination-confirming", + children: interactionState.children, + startWordIndex: Math.min( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ), + endWordIndex: Math.max( + interactionState.anchorWordIndex, + interactionState.focusWordIndex, + ), + }, + sentenceStructureData, + }; + } + case "coordination-confirming": + case "coordination-selected": + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData, + }; + default: { + const _exhaustiveCheck: never = interactionState; + return _exhaustiveCheck; + } + } + case "MOUSE_DOWN_ON_WORD": + switch (interactionState.type) { + case "idle": + case "range-selecting": + case "range-confirming": + case "range-selected": + case "relation-selected": + case "coordination-selected": + return { + success: true, + interactionState: { + type: "range-selecting", + anchorWordIndex: action.payload.wordIndex, + focusWordIndex: action.payload.wordIndex, + }, + sentenceStructureData, + }; + case "relation-idle": + case "relation-selecting": + return { + success: true, + interactionState: { + type: "relation-selecting", + fromRange: interactionState.fromRange, + anchorWordIndex: action.payload.wordIndex, + focusWordIndex: action.payload.wordIndex, + }, + sentenceStructureData, + }; + case "coordination-idle": + case "coordination-selecting": + case "coordination-confirming": + if (interactionState.children.length === 0) { + return { + success: true, + interactionState: { + type: "range-selecting", + anchorWordIndex: action.payload.wordIndex, + focusWordIndex: action.payload.wordIndex, + }, + sentenceStructureData, + }; + } + return { + success: true, + interactionState: { + type: "coordination-selecting", + children: interactionState.children, + anchorWordIndex: action.payload.wordIndex, + focusWordIndex: action.payload.wordIndex, + }, + sentenceStructureData, + }; + default: { + const _exhaustiveCheck: never = interactionState; + return _exhaustiveCheck; + } + } + case "MOUSE_ENTER_ON_WORD": + switch (interactionState.type) { + case "idle": + return { + success: true, + interactionState, + sentenceStructureData, + }; + case "range-selecting": + return { + success: true, + interactionState: { + type: "range-selecting", + anchorWordIndex: interactionState.anchorWordIndex, + focusWordIndex: action.payload.wordIndex, + }, + sentenceStructureData, + }; + case "range-confirming": + case "range-selected": + case "relation-idle": + return { + success: true, + interactionState, + sentenceStructureData, + }; + case "relation-selecting": + return { + success: true, + interactionState: { + type: "relation-selecting", + fromRange: interactionState.fromRange, + anchorWordIndex: interactionState.anchorWordIndex, + focusWordIndex: action.payload.wordIndex, + }, + sentenceStructureData, + }; + case "relation-selected": + case "coordination-idle": + return { + success: true, + interactionState, + sentenceStructureData, + }; + case "coordination-selecting": + return { + success: true, + interactionState: { + type: "coordination-selecting", + children: interactionState.children, + anchorWordIndex: interactionState.anchorWordIndex, + focusWordIndex: action.payload.wordIndex, + }, + sentenceStructureData, + }; + case "coordination-confirming": + case "coordination-selected": + return { + success: true, + interactionState, + sentenceStructureData, + }; + default: { + const _exhaustiveCheck: never = interactionState; + return _exhaustiveCheck; + } + } + case "MOUSE_UP_ON_WORD": + switch (interactionState.type) { + case "idle": + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData, + }; + case "range-selecting": { + const matchedRange = findRangeByStartAndEndWordIndex( + sentenceStructureData, + { + startWordIndex: Math.min( + interactionState.anchorWordIndex, + action.payload.wordIndex, + ), + endWordIndex: Math.max( + interactionState.anchorWordIndex, + action.payload.wordIndex, + ), + }, + ); + if (matchedRange) { + return { + success: true, + interactionState: { + type: "range-selected", + rangeType: matchedRange.type, + rangeId: matchedRange.id, + }, + sentenceStructureData, + }; + } else { + return { + success: true, + interactionState: { + type: "range-confirming", + startWordIndex: Math.min( + interactionState.anchorWordIndex, + action.payload.wordIndex, + ), + endWordIndex: Math.max( + interactionState.anchorWordIndex, + action.payload.wordIndex, + ), + }, + sentenceStructureData, + }; + } + } + case "range-confirming": + case "range-selected": + case "relation-idle": + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData, + }; + case "relation-selecting": { + const newSentenceStructureData = createRelation( + sentenceStructureData, + { + fromRange: interactionState.fromRange, + toRange: { + startWordIndex: Math.min( + interactionState.anchorWordIndex, + action.payload.wordIndex, + ), + endWordIndex: Math.max( + interactionState.anchorWordIndex, + action.payload.wordIndex, + ), + }, + }, + ); + if (newSentenceStructureData.success) { + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData: + newSentenceStructureData.data.newSentenceStructureData, + }; + } else { + return { + success: false, + message: newSentenceStructureData.message, + }; + } + } + case "relation-selected": + case "coordination-idle": + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData, + }; + case "coordination-selecting": { + return { + success: true, + interactionState: { + type: "coordination-confirming", + children: interactionState.children, + startWordIndex: Math.min( + interactionState.anchorWordIndex, + action.payload.wordIndex, + ), + endWordIndex: Math.max( + interactionState.anchorWordIndex, + action.payload.wordIndex, + ), + }, + sentenceStructureData, + }; + } + case "coordination-confirming": + case "coordination-selected": + return { + success: true, + interactionState: { type: "idle" }, + sentenceStructureData, + }; + default: { + const _exhaustiveCheck: never = interactionState; + return _exhaustiveCheck; + } + } + case "CREATE_SENTENCE_ELEMENT_RANGE": { + if (interactionState.type !== "range-confirming") + throw new Error("Invalid interaction state"); + const result = createSentenceElementRange(sentenceStructureData, { + type: action.payload.rangeType, + startWordIndex: interactionState.startWordIndex, + endWordIndex: interactionState.endWordIndex, + }); + if (result.success) { + return { + success: true, + interactionState: { + type: "range-selected", + rangeType: action.payload.rangeType, + rangeId: result.data.rangeId, + }, + sentenceStructureData: result.data.newSentenceStructureData, + }; + } else { + return { success: false, message: result.message }; + } + } + case "CREATE_SENTENCE_STRUCTURE_RANGE": { + if (interactionState.type !== "range-confirming") + throw new Error("Invalid interaction state"); + const result = createSentenceStructureRange(sentenceStructureData, { + type: action.payload.rangeType, + startWordIndex: interactionState.startWordIndex, + endWordIndex: interactionState.endWordIndex, + }); + if (result.success) { + return { + success: true, + interactionState: { + type: "range-selected", + rangeType: action.payload.rangeType, + rangeId: result.data.rangeId, + }, + sentenceStructureData: result.data.newSentenceStructureData, + }; + } else { + return { success: false, message: result.message }; + } + } + case "CLICK_ON_RANGE": { + const matchedRange = findRangeById(sentenceStructureData, { + rangeId: action.payload.rangeId, + }); + if (!matchedRange) throw new Error("Invalid range ID"); + + return { + success: true, + interactionState: { + type: "range-selected", + rangeType: matchedRange.type, + rangeId: action.payload.rangeId, + }, + sentenceStructureData, + }; + } + case "UPDATE_SENTENCE_ELEMENT_NAME": + if (interactionState.type !== "range-selected") + throw new Error("Invalid interaction state"); + return { + success: true, + interactionState, + sentenceStructureData: updateSentenceElementName< + typeof interactionState.rangeType + >(sentenceStructureData, { + rangeId: interactionState.rangeId, + sentenceElementName: action.payload.sentenceElementName, + }), + }; + case "DELETE_RANGE": + if (interactionState.type !== "range-selected") + throw new Error("Invalid interaction state"); + return { + success: true, + interactionState: { + type: "idle", + }, + sentenceStructureData: deleteRange(sentenceStructureData, { + rangeId: interactionState.rangeId, + }), + }; + case "START_CREATING_RELATION": { + if ( + interactionState.type !== "range-confirming" && + interactionState.type !== "range-selected" + ) + throw new Error("Invalid interaction state"); + const fromRange = + interactionState.type === "range-confirming" + ? { + startWordIndex: interactionState.startWordIndex, + endWordIndex: interactionState.endWordIndex, + } + : findRangeById(sentenceStructureData, { + rangeId: interactionState.rangeId, + }); + if (!fromRange) throw new Error("Invalid range ID"); + return { + success: true, + interactionState: { + type: "relation-idle", + fromRange, + }, + sentenceStructureData, + }; + } + case "CANCEL_CREATING_RELATION": { + if ( + interactionState.type !== "relation-idle" && + interactionState.type !== "relation-selecting" + ) + throw new Error("Invalid interaction state"); + const fromRange = findRangeByStartAndEndWordIndex(sentenceStructureData, { + startWordIndex: interactionState.fromRange.startWordIndex, + endWordIndex: interactionState.fromRange.endWordIndex, + }); + if (fromRange) { + return { + success: true, + interactionState: { + type: "range-selected", + rangeType: fromRange.type, + rangeId: fromRange.id, + }, + sentenceStructureData, + }; + } else { + return { + success: true, + interactionState: { + type: "idle", + }, + sentenceStructureData, + }; + } + } + case "CLICK_ON_RELATION": + return { + success: true, + interactionState: { + type: "relation-selected", + relationId: action.payload.relationId, + }, + sentenceStructureData, + }; + case "DELETE_RELATION": + if (interactionState.type !== "relation-selected") + throw new Error("Invalid interaction state"); + return { + success: true, + interactionState: { + type: "idle", + }, + sentenceStructureData: deleteRelation(sentenceStructureData, { + relationId: interactionState.relationId, + }), + }; + case "START_CREATING_COORDINATION": + if ( + interactionState.type !== "range-confirming" && + interactionState.type !== "range-selected" + ) + throw new Error("Invalid interaction state"); + switch (interactionState.type) { + case "range-confirming": + return { + success: true, + interactionState: { + type: "coordination-confirming", + children: [], + startWordIndex: interactionState.startWordIndex, + endWordIndex: interactionState.endWordIndex, + }, + sentenceStructureData, + }; + case "range-selected": { + const selectingRange = findRangeById(sentenceStructureData, { + rangeId: interactionState.rangeId, + }); + if (!selectingRange) throw new Error("Invalid range ID"); + return { + success: true, + interactionState: { + type: "coordination-confirming", + children: [], + startWordIndex: selectingRange.startWordIndex, + endWordIndex: selectingRange.endWordIndex, + }, + sentenceStructureData, + }; + } + default: { + const _exhaustiveCheck: never = interactionState; + return _exhaustiveCheck; + } + } + case "CREATE_COORDINATION_CHILD": + if (interactionState.type !== "coordination-confirming") + throw new Error("Invalid interaction state"); + return { + success: true, + interactionState: { + type: "coordination-idle", + children: [ + ...interactionState.children, + { + type: action.payload.coordinationChildType, + startWordIndex: interactionState.startWordIndex, + endWordIndex: interactionState.endWordIndex, + }, + ], + }, + sentenceStructureData, + }; + case "CONFIRM_CREATING_COORDINATION": { + if ( + interactionState.type !== "coordination-idle" && + interactionState.type !== "coordination-selecting" + ) + throw new Error("Invalid interaction state"); + const result = createCoordination(sentenceStructureData, { + children: interactionState.children, + }); + if (result.success) { + return { + success: true, + interactionState: { + type: "idle", + }, + sentenceStructureData: result.data.newSentenceStructureData, + }; + } else { + return { success: false, message: result.message }; + } + } + case "CANCEL_CREATING_COORDINATION": + if ( + interactionState.type !== "coordination-idle" && + interactionState.type !== "coordination-selecting" + ) + throw new Error("Invalid interaction state"); + return { + success: true, + interactionState: { + type: "idle", + }, + sentenceStructureData, + }; + case "CLICK_ON_COORDINATION": + return { + success: true, + interactionState: { + type: "coordination-selected", + coordinationId: action.payload.coordinationId, + }, + sentenceStructureData, + }; + case "DELETE_COORDINATION": + if (interactionState.type !== "coordination-selected") + throw new Error("Invalid interaction state"); + return { + success: true, + interactionState: { + type: "idle", + }, + sentenceStructureData: deleteCoordination(sentenceStructureData, { + coordinationId: interactionState.coordinationId, + }), + }; + default: { + const _exhaustiveCheck: never = action; + return _exhaustiveCheck; + } + } +} + +type InteractionStateContextValue = { + interactionState: InteractionState; + handleMouseUpOutsideWord: () => + | { success: true } + | { success: false; message: string }; + handleMouseDownOnWord: ( + wordIndex: number, + ) => { success: true } | { success: false; message: string }; + handleMouseEnterOnWord: ( + wordIndex: number, + ) => { success: true } | { success: false; message: string }; + handleMouseUpOnWord: ( + wordIndex: number, + ) => { success: true } | { success: false; message: string }; + handleCreateSentenceElementRange: ( + rangeType: SentenceElementRangeType, + ) => { success: true } | { success: false; message: string }; + handleCreateSentenceStructureRange: ( + rangeType: SentenceStructureRangeType, + ) => { success: true } | { success: false; message: string }; + handleClickOnRange: ( + rangeId: string, + ) => { success: true } | { success: false; message: string }; + handleUpdateSentenceElementName: ( + sentenceElementName: SentenceElementName, + ) => { success: true } | { success: false; message: string }; + handleDeleteRange: () => + | { success: true } + | { success: false; message: string }; + handleStartCreatingRelation: () => + | { success: true } + | { success: false; message: string }; + handleCancelCreatingRelation: () => + | { success: true } + | { success: false; message: string }; + handleClickOnRelation: ( + relationId: string, + ) => { success: true } | { success: false; message: string }; + handleDeleteRelation: () => + | { success: true } + | { success: false; message: string }; + handleStartCreatingCoordination: () => + | { success: true } + | { success: false; message: string }; + handleCreateCoordinationChild: ( + coordinationChildType: CoordinationChildType, + ) => { success: true } | { success: false; message: string }; + handleConfirmCreatingCoordination: () => + | { success: true } + | { success: false; message: string }; + handleCancelCreatingCoordination: () => + | { success: true } + | { success: false; message: string }; + handleClickOnCoordination: ( + coordinationId: string, + ) => { success: true } | { success: false; message: string }; + handleDeleteCoordination: () => + | { success: true } + | { success: false; message: string }; +}; + +const InteractionStateContext = + createContext(null); + +export function InteractionStateProvider(props: PropsWithChildren) { + const [interactionState, setInteractionState] = useState({ + type: "idle", + }); + const { sentenceStructureData, setSentenceStructureData } = + useSentenceStructureData(); + + return ( + { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "MOUSE_UP_OUTSIDE_WORD" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleMouseDownOnWord: (wordIndex: number) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "MOUSE_DOWN_ON_WORD", payload: { wordIndex } }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleMouseEnterOnWord: (wordIndex: number) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "MOUSE_ENTER_ON_WORD", payload: { wordIndex } }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleMouseUpOnWord: (wordIndex: number) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "MOUSE_UP_ON_WORD", payload: { wordIndex } }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleCreateSentenceElementRange: (rangeType) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { + type: "CREATE_SENTENCE_ELEMENT_RANGE", + payload: { rangeType }, + }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleCreateSentenceStructureRange: (rangeType) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { + type: "CREATE_SENTENCE_STRUCTURE_RANGE", + payload: { rangeType }, + }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleClickOnRange: (rangeId: string) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "CLICK_ON_RANGE", payload: { rangeId } }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleUpdateSentenceElementName: (sentenceElementName) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { + type: "UPDATE_SENTENCE_ELEMENT_NAME", + payload: { sentenceElementName }, + }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleDeleteRange: () => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "DELETE_RANGE" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleStartCreatingRelation: () => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "START_CREATING_RELATION" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleCancelCreatingRelation: () => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "CANCEL_CREATING_RELATION" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleClickOnRelation: (relationId: string) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "CLICK_ON_RELATION", payload: { relationId } }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleDeleteRelation: () => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "DELETE_RELATION" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleStartCreatingCoordination: () => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "START_CREATING_COORDINATION" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleCreateCoordinationChild: (coordinationChildType) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { + type: "CREATE_COORDINATION_CHILD", + payload: { coordinationChildType }, + }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleConfirmCreatingCoordination: () => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "CONFIRM_CREATING_COORDINATION" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleCancelCreatingCoordination: () => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "CANCEL_CREATING_COORDINATION" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleClickOnCoordination: (coordinationId: string) => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "CLICK_ON_COORDINATION", payload: { coordinationId } }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + handleDeleteCoordination: () => { + const result = interactionStateReducer( + interactionState, + sentenceStructureData, + { type: "DELETE_COORDINATION" }, + ); + if (result.success) { + setInteractionState(result.interactionState); + setSentenceStructureData(result.sentenceStructureData); + return { success: true }; + } else { + return { success: false, message: result.message }; + } + }, + }} + > + {props.children} + + ); +} + +// eslint-disable-next-line react-refresh/only-export-components +export function useInteractionState() { + const context = useContext(InteractionStateContext); + if (!context) { + throw new Error( + "useInteractionState must be used within a InteractionStateProvider", + ); + } + return context; +} diff --git a/packages/frontend/src/pages/contexts/SentenceStructureDataProvider.tsx b/packages/frontend/src/pages/contexts/SentenceStructureDataProvider.tsx new file mode 100644 index 0000000..c23e6b5 --- /dev/null +++ b/packages/frontend/src/pages/contexts/SentenceStructureDataProvider.tsx @@ -0,0 +1,82 @@ +import { + createContext, + useContext, + useState, + type PropsWithChildren, +} from "react"; +import { + createSentenceStructureDataFromStringData, + createSentenceStructureDataFromText, + sentenceStructureDataToString, + type SentenceStructureData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; + +const initialText = ""; + +type SentenceStructureDataContextValue = { + initialSentenceStructureData: SentenceStructureData; + sentenceStructureData: SentenceStructureData; + setSentenceStructureData: ( + newSentenceStructureData: SentenceStructureData, + ) => void; +}; + +const SentenceStructureDataContext = + createContext(null); + +export function SentenceStructureDataProvider(props: PropsWithChildren) { + const [sentenceStructureData, _setSentenceStructureData] = + useState(() => { + const savedSentenceStructureData = localStorage.getItem( + "sentenceStructureData", + ); + if (!savedSentenceStructureData) { + return createSentenceStructureDataFromText({ text: initialText }); + } + const result = createSentenceStructureDataFromStringData( + savedSentenceStructureData, + ); + if (result.success) { + return result.data.newSentenceStructureData; + } else { + return createSentenceStructureDataFromText({ + text: initialText, + }); + } + }); + + function setSentenceStructureData( + newSentenceStructureData: SentenceStructureData, + ) { + localStorage.setItem( + "sentenceStructureData", + sentenceStructureDataToString(newSentenceStructureData), + ); + _setSentenceStructureData(newSentenceStructureData); + } + + return ( + + {props.children} + + ); +} + +// eslint-disable-next-line react-refresh/only-export-components +export function useSentenceStructureData() { + const context = useContext(SentenceStructureDataContext); + if (!context) { + throw new Error( + "useSentenceStructureData must be used within a SentenceStructureDataProvider", + ); + } + return context; +} diff --git a/packages/frontend/src/pages/index.tsx b/packages/frontend/src/pages/index.tsx new file mode 100644 index 0000000..484f748 --- /dev/null +++ b/packages/frontend/src/pages/index.tsx @@ -0,0 +1,16 @@ +import { SentenceStructureDataProvider } from "./contexts/SentenceStructureDataProvider"; +import { ConfigurationsProvider } from "./contexts/ConfigurationsProvider"; +import { InteractionStateProvider } from "./contexts/InteractionStateProvider"; +import SentenceStructureEditor from "./components/SentenceStructureEditor"; + +export default function Home() { + return ( + + + + + + + + ); +} diff --git a/packages/frontend/src/pages/utils/measure-text-width.ts b/packages/frontend/src/pages/utils/measure-text-width.ts new file mode 100644 index 0000000..18b4f8c --- /dev/null +++ b/packages/frontend/src/pages/utils/measure-text-width.ts @@ -0,0 +1,9 @@ +export function measureTextWidth(text: string): number { + const canvas = document.createElement("canvas"); + const context = canvas.getContext("2d"); + if (!context) return 0; + context.font = "16px system-ui"; + + const metrics = context.measureText(text); + return metrics.width; +} diff --git a/packages/frontend/src/utils/trpc.ts b/packages/frontend/src/utils/trpc.ts new file mode 100644 index 0000000..9537fa1 --- /dev/null +++ b/packages/frontend/src/utils/trpc.ts @@ -0,0 +1,15 @@ +import { createTRPCClient, httpBatchLink } from "@trpc/client"; +import { QueryClient } from "@tanstack/react-query"; +import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query"; +import type { AppRouter } from "@sentence-structure-diagram-app/backend"; + +export const queryClient = new QueryClient(); + +const trpcClient = createTRPCClient({ + links: [httpBatchLink({ url: `${import.meta.env.VITE_API_ENDPOINT}/trpc` })], +}); + +export const trpc = createTRPCOptionsProxy({ + client: trpcClient, + queryClient, +}); diff --git a/tsconfig.app.json b/packages/frontend/tsconfig.app.json similarity index 100% rename from tsconfig.app.json rename to packages/frontend/tsconfig.app.json diff --git a/tsconfig.json b/packages/frontend/tsconfig.json similarity index 100% rename from tsconfig.json rename to packages/frontend/tsconfig.json diff --git a/tsconfig.node.json b/packages/frontend/tsconfig.node.json similarity index 100% rename from tsconfig.node.json rename to packages/frontend/tsconfig.node.json diff --git a/vite.config.ts b/packages/frontend/vite.config.ts similarity index 81% rename from vite.config.ts rename to packages/frontend/vite.config.ts index 0e43ae8..9313147 100644 --- a/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -4,4 +4,5 @@ import react from "@vitejs/plugin-react"; // https://vite.dev/config/ export default defineConfig({ plugins: [react()], + base: process.env.BASE_URL || "/", }); diff --git a/packages/sentence-structure-data/.gitignore b/packages/sentence-structure-data/.gitignore new file mode 100644 index 0000000..9b1c8b1 --- /dev/null +++ b/packages/sentence-structure-data/.gitignore @@ -0,0 +1 @@ +/dist diff --git a/packages/sentence-structure-data/format.ts b/packages/sentence-structure-data/format.ts new file mode 100644 index 0000000..9881db6 --- /dev/null +++ b/packages/sentence-structure-data/format.ts @@ -0,0 +1,281 @@ +import * as z from "zod"; +import { XMLBuilder, XMLParser } from "fast-xml-parser"; +import { + sentenceElementRangeTypeOptions, + SentenceStructureDataSchema, + type Coordination, + type CoordinationChildType, + type Range, + type Relation, + type SentenceElementRangeType, + type SentenceStructureRangeType, +} from "./schema.js"; +import { + SimplifiedSentenceStructureDataSchema, + type SimplifiedSentenceStructureData, +} from "./simplified-schema.js"; + +const sentenceElementRangeTypePairs = [ + ["core-sentence-element", "文の主要素"], +] as const satisfies [SentenceElementRangeType, string][]; +const sentenceElementRangeTypeToSimplifiedSentenceElementRangeTypeMap = new Map( + sentenceElementRangeTypePairs, +); +const simplifiedSentenceElementRangeTypeToSentenceElementRangeTypeMap = new Map( + sentenceElementRangeTypePairs.map(([a, b]) => [b, a]), +); + +const sentenceStructureRangeTypePairs = [ + ["modifier", "修飾語"], + ["phrase", "句"], + ["clause", "節"], +] as const satisfies [SentenceStructureRangeType, string][]; +const sentenceStructureRangeTypeToSimplifiedSentenceStructureRangeTypeMap = + new Map(sentenceStructureRangeTypePairs); +const simplifiedSentenceStructureRangeTypeToSentenceStructureRangeTypeMap = + new Map(sentenceStructureRangeTypePairs.map(([a, b]) => [b, a])); + +const coordinationChildTypePairs = [ + ["coordinating conjunction", "等位接続詞"], + ["correlative conjunction", "相関接続詞"], + ["conjunct", "並列要素"], +] as const satisfies [CoordinationChildType, string][]; +const coordinationChildTypeToSimplifiedCoordinationChildTypeMap = new Map( + coordinationChildTypePairs, +); +const simplifiedCoordinationChildTypeToCoordinationChildTypeMap = new Map( + coordinationChildTypePairs.map(([a, b]) => [b, a]), +); + +export const simplifiedSentenceStructureDataToSentenceStructureData = z.codec( + SimplifiedSentenceStructureDataSchema, + SentenceStructureDataSchema, + { + decode: (simplifiedSentenceStructureData) => { + const sortedSimplifiedSentenceStructureData = { + text: simplifiedSentenceStructureData.text, + words: simplifiedSentenceStructureData.words.sort( + (a, b) => a.index - b.index, + ), + ranges: simplifiedSentenceStructureData.ranges.sort( + (a, b) => a.index - b.index, + ), + relations: simplifiedSentenceStructureData.relations, + coordinations: simplifiedSentenceStructureData.coordinations.map( + (coordination) => ({ + children: coordination.children.sort( + (a, b) => a.startWordIndex - b.startWordIndex, + ), + }), + ), + }; + const rangeIds = sortedSimplifiedSentenceStructureData.ranges.map(() => + crypto.randomUUID(), + ); + + return { + text: sortedSimplifiedSentenceStructureData.text, + words: sortedSimplifiedSentenceStructureData.words, + ranges: sortedSimplifiedSentenceStructureData.ranges.map((range) => + range.type === "関係" + ? { + kind: "relation", + type: "relation", + id: rangeIds[range.index]!, + startWordIndex: range.startWordIndex, + endWordIndex: range.endWordIndex, + } + : sentenceElementRangeTypeOptions.includes( + simplifiedSentenceElementRangeTypeToSentenceElementRangeTypeMap.get( + range.type as any, + )!, + ) + ? { + kind: "sentence-element", + type: simplifiedSentenceElementRangeTypeToSentenceElementRangeTypeMap.get( + range.type as any, + )!, + id: rangeIds[range.index]!, + startWordIndex: range.startWordIndex, + endWordIndex: range.endWordIndex, + sentenceElementName: range.sentenceElementName, + } + : { + kind: "sentence-structure", + type: simplifiedSentenceStructureRangeTypeToSentenceStructureRangeTypeMap.get( + range.type as any, + )!, + id: rangeIds[range.index]!, + startWordIndex: range.startWordIndex, + endWordIndex: range.endWordIndex, + sentenceElementName: range.sentenceElementName, + }, + ) as Range[], + relations: sortedSimplifiedSentenceStructureData.relations.map( + (relation) => { + return { + id: crypto.randomUUID(), + fromRangeId: rangeIds[relation.fromRangeIndex]!, + toRangeId: rangeIds[relation.toRangeIndex]!, + }; + }, + ) satisfies Relation[], + coordinations: sortedSimplifiedSentenceStructureData.coordinations.map( + (coordination) => ({ + id: crypto.randomUUID(), + children: coordination.children.map((child, index) => ({ + type: simplifiedCoordinationChildTypeToCoordinationChildTypeMap.get( + child.type, + )!, + index: index, + startWordIndex: child.startWordIndex, + endWordIndex: child.endWordIndex, + })), + }), + ) satisfies Coordination[], + }; + }, + encode: (sentenceStructureData) => { + const sortedSentenceStructureData = { + ...sentenceStructureData, + words: sentenceStructureData.words.sort((a, b) => a.index - b.index), + ranges: sentenceStructureData.ranges.sort((a, b) => { + if (a.startWordIndex !== b.startWordIndex) { + return a.startWordIndex - b.startWordIndex; + } + return b.endWordIndex - a.endWordIndex; + }), + relations: sentenceStructureData.relations, + coordinations: sentenceStructureData.coordinations + .map((coordination) => ({ + children: coordination.children.sort((a, b) => a.index - b.index), + })) + .sort((a, b) => { + if ( + a.children.at(0)!.startWordIndex !== + b.children.at(0)!.startWordIndex + ) { + return ( + a.children.at(0)!.startWordIndex - + b.children.at(0)!.startWordIndex + ); + } + return ( + b.children.at(-1)!.endWordIndex - a.children.at(-1)!.endWordIndex + ); + }), + }; + return { + text: sortedSentenceStructureData.text, + words: sortedSentenceStructureData.words, + ranges: sortedSentenceStructureData.ranges.map((range, index) => + range.kind === "relation" + ? { + type: "関係", + index: index, + startWordIndex: range.startWordIndex, + endWordIndex: range.endWordIndex, + } + : { + type: + range.kind === "sentence-element" + ? sentenceElementRangeTypeToSimplifiedSentenceElementRangeTypeMap.get( + range.type, + )! + : sentenceStructureRangeTypeToSimplifiedSentenceStructureRangeTypeMap.get( + range.type, + )!, + index: index, + startWordIndex: range.startWordIndex, + endWordIndex: range.endWordIndex, + sentenceElementName: range.sentenceElementName, + }, + ) as SimplifiedSentenceStructureData["ranges"], + relations: ( + sortedSentenceStructureData.relations.map((relation) => ({ + fromRangeIndex: sortedSentenceStructureData.ranges.findIndex( + (range) => range.id === relation.fromRangeId, + ), + toRangeIndex: sortedSentenceStructureData.ranges.findIndex( + (range) => range.id === relation.toRangeId, + ), + })) satisfies SimplifiedSentenceStructureData["relations"] + ).sort((a, b) => { + if (a.fromRangeIndex !== b.fromRangeIndex) { + return a.fromRangeIndex - b.fromRangeIndex; + } + return b.toRangeIndex - a.toRangeIndex; + }), + coordinations: sortedSentenceStructureData.coordinations.map( + (coordination) => ({ + children: coordination.children.map((child) => ({ + type: coordinationChildTypeToSimplifiedCoordinationChildTypeMap.get( + child.type, + )!, + startWordIndex: child.startWordIndex, + endWordIndex: child.endWordIndex, + })), + }), + ) satisfies SimplifiedSentenceStructureData["coordinations"], + }; + }, + }, +); + +export const stringToSentenceStructureData = z.codec( + z.string(), + SentenceStructureDataSchema, + { + decode: (string) => + simplifiedSentenceStructureDataToSentenceStructureData.decode( + JSON.parse(string), + ), + encode: (sentenceStructureData) => + JSON.stringify( + simplifiedSentenceStructureDataToSentenceStructureData.encode( + sentenceStructureData, + ), + null, + 2, + ), + }, +); + +export const xmlStringToSentenceStructureData = z.codec( + z.string(), + SentenceStructureDataSchema, + { + decode: (xml) => { + const parsed = new XMLParser({ + isArray: (tagName) => + [ + "words", + "ranges", + "relations", + "coordinations", + "children", + ].includes(tagName), + }).parse(xml); + return simplifiedSentenceStructureDataToSentenceStructureData.decode({ + words: [], + relations: [], + coordinations: [], + ...parsed, + ranges: + parsed.ranges?.map((range: any) => ({ + ...range, + sentenceElementName: + range.sentenceElementName === "" + ? null + : range.sentenceElementName, + })) ?? [], + }); + }, + encode: (sentenceStructureData) => + new XMLBuilder({ format: true }).build( + simplifiedSentenceStructureDataToSentenceStructureData.encode( + sentenceStructureData, + ), + ), + }, +); diff --git a/packages/sentence-structure-data/index.ts b/packages/sentence-structure-data/index.ts new file mode 100644 index 0000000..db80ee6 --- /dev/null +++ b/packages/sentence-structure-data/index.ts @@ -0,0 +1,47 @@ +export { + sentenceElementNameOptions, + sentenceElementRangeTypeOptions, + sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap, + sentenceStructureRangeTypeOptions, + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap, + coordinationChildTypeOptions, + SentenceStructureDataSchema, + type Word, + type SentenceElementName, + type SentenceElementRangeType, + type SentenceStructureRangeType, + type RangeType, + type Range, + type Relation, + type CoordinationChildType, + type CoordinationChild, + type Coordination, + type SentenceStructureData, +} from "./schema.js"; +export { + SimplifiedAnnotationDataSchema, + SimplifiedSentenceStructureDataSchema, + type SimplifiedAnnotationData, + type SimplifiedSentenceStructureData, +} from "./simplified-schema.js"; +export { + createSentenceStructureDataFromText, + createSentenceStructureDataFromStringData, + createSentenceStructureDataFromXMLData, + createSentenceStructureDataFromSimplifiedAnnotationData, + sentenceStructureDataToString, + sentenceStructureDataToXMLString, + createSentenceElementRange, + createSentenceStructureRange, + findRangeById, + findRangeByStartAndEndWordIndex, + updateSentenceElementName, + deleteRange, + createRelation, + findRelationById, + deleteRelation, + createCoordination, + findCoordinationById, + findCoordinationByStartAndEndWordIndex, + deleteCoordination, +} from "./operations.js"; diff --git a/packages/sentence-structure-data/operations.ts b/packages/sentence-structure-data/operations.ts new file mode 100644 index 0000000..58065bd --- /dev/null +++ b/packages/sentence-structure-data/operations.ts @@ -0,0 +1,559 @@ +import { + sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap, + SentenceStructureDataSchema, + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap, + type Coordination, + type CoordinationChildType, + type Range, + type Relation, + type SentenceElementRangeType, + type SentenceStructureData, + type SentenceStructureRangeType, +} from "./schema.js"; +import { + simplifiedSentenceStructureDataToSentenceStructureData, + stringToSentenceStructureData, + xmlStringToSentenceStructureData, +} from "./format.js"; +import { tokenizeText } from "./tokenize-text.js"; +import type { + SimplifiedAnnotationData, + SimplifiedSentenceStructureData, +} from "./simplified-schema.js"; + +type Result = + | { + success: true; + data: T; + } + | { + success: false; + message: string; + }; + +export function createSentenceStructureDataFromText(input: { + text: string; +}): SentenceStructureData { + return SentenceStructureDataSchema.parse({ + text: input.text, + words: tokenizeText(input.text), + ranges: [], + relations: [], + coordinations: [], + } satisfies SentenceStructureData); +} + +export function createSentenceStructureDataFromStringData( + string: string, +): Result<{ newSentenceStructureData: SentenceStructureData }> { + const newSentenceStructureData = + stringToSentenceStructureData.safeDecode(string); + + if (newSentenceStructureData.success) { + return { + success: true, + data: { + newSentenceStructureData: newSentenceStructureData.data, + }, + }; + } + const errorMessage = + newSentenceStructureData.error.issues.find( + (issue) => issue.code === "custom", + )?.message ?? null; + if (errorMessage) { + return { + success: false, + message: errorMessage, + }; + } + return { + success: false, + message: "フォーマットが正しくありません。", + }; +} + +export function createSentenceStructureDataFromXMLData( + xmlString: string, +): Result<{ newSentenceStructureData: SentenceStructureData }> { + const newSentenceStructureData = + xmlStringToSentenceStructureData.safeDecode(xmlString); + + if (newSentenceStructureData.success) { + return { + success: true, + data: { + newSentenceStructureData: newSentenceStructureData.data, + }, + }; + } + const errorMessage = + newSentenceStructureData.error.issues.find( + (issue) => issue.code === "custom", + )?.message ?? null; + if (errorMessage) { + return { + success: false, + message: errorMessage, + }; + } + return { + success: false, + message: "フォーマットが正しくありません。", + }; +} + +export function createSentenceStructureDataFromSimplifiedAnnotationData( + text: string, + simplifiedAnnotationData: SimplifiedAnnotationData, +): Result<{ newSentenceStructureData: SentenceStructureData }> { + const simplifiedSentenceStructureData: SimplifiedSentenceStructureData = { + text: text, + words: tokenizeText(text), + ...simplifiedAnnotationData, + }; + const newSentenceStructureData = + simplifiedSentenceStructureDataToSentenceStructureData.safeDecode( + simplifiedSentenceStructureData, + ); + + if (newSentenceStructureData.success) { + return { + success: true, + data: { + newSentenceStructureData: newSentenceStructureData.data, + }, + }; + } + const errorMessage = + newSentenceStructureData.error.issues.find( + (issue) => issue.code === "custom", + )?.message ?? null; + if (errorMessage) { + return { + success: false, + message: errorMessage, + }; + } + throw newSentenceStructureData.error; +} + +export function sentenceStructureDataToString( + sentenceStructureData: SentenceStructureData, +): string { + return stringToSentenceStructureData.encode(sentenceStructureData); +} + +export function sentenceStructureDataToXMLString( + sentenceStructureData: SentenceStructureData, +): string { + return xmlStringToSentenceStructureData.encode(sentenceStructureData); +} + +export function createSentenceElementRange( + sentenceStructureData: SentenceStructureData, + input: { + type: SentenceElementRangeType; + startWordIndex: number; + endWordIndex: number; + }, +): Result<{ + newSentenceStructureData: SentenceStructureData; + rangeId: string; +}> { + const rangeId = crypto.randomUUID(); + const newSentenceStructureData = SentenceStructureDataSchema.safeParse({ + ...sentenceStructureData, + ranges: [ + ...sentenceStructureData.ranges, + { + kind: "sentence-element", + type: input.type, + id: rangeId, + startWordIndex: input.startWordIndex, + endWordIndex: input.endWordIndex, + sentenceElementName: null, + }, + ], + } satisfies SentenceStructureData); + + if (newSentenceStructureData.success) { + return { + success: true, + data: { + newSentenceStructureData: newSentenceStructureData.data, + rangeId, + }, + }; + } + const errorMessage = + newSentenceStructureData.error.issues.find( + (issue) => issue.code === "custom", + )?.message ?? null; + if (errorMessage) { + return { + success: false, + message: errorMessage, + }; + } + throw newSentenceStructureData.error; +} + +export function createSentenceStructureRange( + sentenceStructureData: SentenceStructureData, + input: { + type: SentenceStructureRangeType; + startWordIndex: number; + endWordIndex: number; + }, +): Result<{ + newSentenceStructureData: SentenceStructureData; + rangeId: string; +}> { + const rangeId = crypto.randomUUID(); + const newSentenceStructureData = SentenceStructureDataSchema.safeParse({ + ...sentenceStructureData, + ranges: [ + ...sentenceStructureData.ranges, + { + kind: "sentence-structure", + type: input.type, + id: rangeId, + startWordIndex: input.startWordIndex, + endWordIndex: input.endWordIndex, + sentenceElementName: null, + }, + ], + } satisfies SentenceStructureData); + + if (newSentenceStructureData.success) { + return { + success: true, + data: { + newSentenceStructureData: newSentenceStructureData.data, + rangeId, + }, + }; + } + const errorMessage = + newSentenceStructureData.error.issues.find( + (issue) => issue.code === "custom", + )?.message ?? null; + if (errorMessage) { + return { + success: false, + message: errorMessage, + }; + } + throw newSentenceStructureData.error; +} + +export function _createRelationRange( + sentenceStructureData: SentenceStructureData, + input: { + startWordIndex: number; + endWordIndex: number; + }, +): Result<{ + newSentenceStructureData: SentenceStructureData; + rangeId: string; +}> { + const rangeId = crypto.randomUUID(); + const newSentenceStructureData = SentenceStructureDataSchema.safeParse({ + ...sentenceStructureData, + ranges: [ + ...sentenceStructureData.ranges, + { + kind: "relation", + type: "relation", + id: rangeId, + startWordIndex: input.startWordIndex, + endWordIndex: input.endWordIndex, + }, + ], + } satisfies SentenceStructureData); + + if (newSentenceStructureData.success) { + return { + success: true, + data: { + newSentenceStructureData: newSentenceStructureData.data, + rangeId, + }, + }; + } + const errorMessage = + newSentenceStructureData.error.issues.find( + (issue) => issue.code === "custom", + )?.message ?? null; + if (errorMessage) { + return { + success: false, + message: errorMessage, + }; + } + throw newSentenceStructureData.error; +} + +export function findRangeById( + sentenceStructureData: SentenceStructureData, + input: { rangeId: string }, +): Range | null { + return ( + sentenceStructureData.ranges.find((range) => range.id === input.rangeId) ?? + null + ); +} + +export function findRangeByStartAndEndWordIndex( + sentenceStructureData: SentenceStructureData, + input: { startWordIndex: number; endWordIndex: number }, +): Range | null { + return ( + sentenceStructureData.ranges.find( + (range) => + range.startWordIndex === input.startWordIndex && + range.endWordIndex === input.endWordIndex, + ) ?? null + ); +} + +export function updateSentenceElementName( + sentenceStructureData: SentenceStructureData, + input: { + rangeId: string; + sentenceElementName: RangeType extends SentenceElementRangeType + ? (typeof sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap)[RangeType][number] + : RangeType extends SentenceStructureRangeType + ? (typeof sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap)[RangeType][number] + : never; + }, +): SentenceStructureData { + return SentenceStructureDataSchema.parse({ + ...sentenceStructureData, + ranges: sentenceStructureData.ranges.map((range) => + range.id === input.rangeId + ? ({ + ...range, + sentenceElementName: input.sentenceElementName, + } as Range) + : range, + ), + } satisfies SentenceStructureData); +} + +export function deleteRange( + sentenceStructureData: SentenceStructureData, + input: { rangeId: string }, +): SentenceStructureData { + return SentenceStructureDataSchema.parse({ + ...sentenceStructureData, + ranges: sentenceStructureData.ranges.filter( + (range) => range.id !== input.rangeId, + ), + relations: sentenceStructureData.relations.filter( + (relation) => + relation.fromRangeId !== input.rangeId && + relation.toRangeId !== input.rangeId, + ), + } satisfies SentenceStructureData); +} + +export function createRelation( + sentenceStructureData: SentenceStructureData, + input: { + fromRange: { startWordIndex: number; endWordIndex: number }; + toRange: { startWordIndex: number; endWordIndex: number }; + }, +): Result<{ newSentenceStructureData: SentenceStructureData }> { + const fromRangeResult: Result<{ + newSentenceStructureData: SentenceStructureData; + rangeId: string; + }> = (() => { + const existingFromRange = findRangeByStartAndEndWordIndex( + sentenceStructureData, + { + startWordIndex: input.fromRange.startWordIndex, + endWordIndex: input.fromRange.endWordIndex, + }, + ); + if (existingFromRange) { + return { + success: true, + data: { + newSentenceStructureData: sentenceStructureData, + rangeId: existingFromRange.id, + }, + }; + } + return _createRelationRange(sentenceStructureData, { + startWordIndex: input.fromRange.startWordIndex, + endWordIndex: input.fromRange.endWordIndex, + }); + })(); + if (!fromRangeResult.success) { + return { + success: false, + message: fromRangeResult.message, + }; + } + + const toRangeResult: Result<{ + newSentenceStructureData: SentenceStructureData; + rangeId: string; + }> = (() => { + const existingToRange = findRangeByStartAndEndWordIndex( + fromRangeResult.data.newSentenceStructureData, + { + startWordIndex: input.toRange.startWordIndex, + endWordIndex: input.toRange.endWordIndex, + }, + ); + if (existingToRange) { + return { + success: true, + data: { + newSentenceStructureData: + fromRangeResult.data.newSentenceStructureData, + rangeId: existingToRange.id, + }, + }; + } + return _createRelationRange(fromRangeResult.data.newSentenceStructureData, { + startWordIndex: input.toRange.startWordIndex, + endWordIndex: input.toRange.endWordIndex, + }); + })(); + if (!toRangeResult.success) { + return { + success: false, + message: toRangeResult.message, + }; + } + + return { + success: true, + data: { + newSentenceStructureData: SentenceStructureDataSchema.parse({ + ...toRangeResult.data.newSentenceStructureData, + relations: [ + ...toRangeResult.data.newSentenceStructureData.relations, + { + id: crypto.randomUUID(), + fromRangeId: fromRangeResult.data.rangeId, + toRangeId: toRangeResult.data.rangeId, + }, + ], + } satisfies SentenceStructureData), + }, + }; +} + +export function findRelationById( + sentenceStructureData: SentenceStructureData, + input: { relationId: string }, +): Relation | null { + return ( + sentenceStructureData.relations.find( + (relation) => relation.id === input.relationId, + ) ?? null + ); +} + +export function deleteRelation( + sentenceStructureData: SentenceStructureData, + input: { relationId: string }, +): SentenceStructureData { + return SentenceStructureDataSchema.parse({ + ...sentenceStructureData, + relations: sentenceStructureData.relations.filter( + (relation) => relation.id !== input.relationId, + ), + } satisfies SentenceStructureData); +} + +export function createCoordination( + sentenceStructureData: SentenceStructureData, + input: { + children: { + type: CoordinationChildType; + startWordIndex: number; + endWordIndex: number; + }[]; + }, +): Result<{ + newSentenceStructureData: SentenceStructureData; +}> { + const newSentenceStructureData = SentenceStructureDataSchema.safeParse({ + ...sentenceStructureData, + coordinations: [ + ...sentenceStructureData.coordinations, + { + id: crypto.randomUUID(), + children: input.children + .sort((a, b) => a.startWordIndex - b.startWordIndex) + .map((child, index) => ({ + type: child.type, + index, + startWordIndex: child.startWordIndex, + endWordIndex: child.endWordIndex, + })), + }, + ], + } satisfies SentenceStructureData); + if (newSentenceStructureData.success) { + return { + success: true, + data: { + newSentenceStructureData: newSentenceStructureData.data, + }, + }; + } + const errorMessage = + newSentenceStructureData.error.issues.find( + (issue) => issue.code === "custom", + )?.message ?? null; + if (errorMessage) { + return { + success: false, + message: errorMessage, + }; + } + throw newSentenceStructureData.error; +} + +export function findCoordinationById( + sentenceStructureData: SentenceStructureData, + input: { coordinationId: string }, +): Coordination | null { + return ( + sentenceStructureData.coordinations.find( + (coordination) => coordination.id === input.coordinationId, + ) ?? null + ); +} + +export function findCoordinationByStartAndEndWordIndex( + sentenceStructureData: SentenceStructureData, + input: { startWordIndex: number; endWordIndex: number }, +): Coordination | null { + return ( + sentenceStructureData.coordinations.find( + (coordination) => + coordination.children.at(0)!.startWordIndex === input.startWordIndex && + coordination.children.at(-1)!.endWordIndex === input.endWordIndex, + ) ?? null + ); +} + +export function deleteCoordination( + sentenceStructureData: SentenceStructureData, + input: { coordinationId: string }, +): SentenceStructureData { + return SentenceStructureDataSchema.parse({ + ...sentenceStructureData, + coordinations: sentenceStructureData.coordinations.filter( + (coordination) => coordination.id !== input.coordinationId, + ), + } satisfies SentenceStructureData); +} diff --git a/packages/sentence-structure-data/package.json b/packages/sentence-structure-data/package.json new file mode 100644 index 0000000..ecedf55 --- /dev/null +++ b/packages/sentence-structure-data/package.json @@ -0,0 +1,19 @@ +{ + "name": "@sentence-structure-diagram-app/sentence-structure-data", + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "clean": "rm -r dist" + }, + "dependencies": { + "compromise": "^14.14.4", + "fast-xml-parser": "^5.3.2", + "zod": "^4.1.13" + }, + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/packages/sentence-structure-data/schema.ts b/packages/sentence-structure-data/schema.ts new file mode 100644 index 0000000..3210325 --- /dev/null +++ b/packages/sentence-structure-data/schema.ts @@ -0,0 +1,353 @@ +import * as z from "zod"; + +const WordSchema = z.object({ + index: z.int().nonnegative(), + text: z.string(), +}); +export type Word = z.infer; + +export const sentenceElementNameOptions = ["S", "V", "O", "C", "M"] as const; +export type SentenceElementName = (typeof sentenceElementNameOptions)[number]; + +export const sentenceElementRangeTypeOptions = [ + "core-sentence-element", +] as const; +export type SentenceElementRangeType = + (typeof sentenceElementRangeTypeOptions)[number]; +export const sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap = { + "core-sentence-element": ["S", "V", "O", "C"] as const, +} satisfies Record; + +export const sentenceStructureRangeTypeOptions = [ + "modifier", + "phrase", + "clause", +] as const; +export type SentenceStructureRangeType = + (typeof sentenceStructureRangeTypeOptions)[number]; +export const sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap = + { + modifier: ["M"] as const, + phrase: ["S", "O", "C", "M"] as const, + clause: ["S", "O", "C", "M"] as const, + } satisfies Record; + +const relationRangeTypeOption = "relation" as const; +export type RelationRangeType = typeof relationRangeTypeOption; + +export type RangeType = + | SentenceElementRangeType + | SentenceStructureRangeType + | RelationRangeType; + +const RangeSchema = z.union([ + ...sentenceElementRangeTypeOptions.map( + (sentenceElementRangeTypeOption) => + ({ + "core-sentence-element": z.object({ + kind: z.literal("sentence-element"), + type: z.literal("core-sentence-element"), + id: z.uuid(), + startWordIndex: z.int().nonnegative(), + endWordIndex: z.int().nonnegative(), + sentenceElementName: z.nullable( + z.literal( + sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap[ + "core-sentence-element" + ], + ), + ), + }), + })[sentenceElementRangeTypeOption], + ), + ...sentenceStructureRangeTypeOptions.map( + (sentenceStructureRangeTypeOption) => + ({ + modifier: z.object({ + kind: z.literal("sentence-structure"), + type: z.literal("modifier"), + id: z.uuid(), + startWordIndex: z.int().nonnegative(), + endWordIndex: z.int().nonnegative(), + sentenceElementName: z.nullable( + z.literal( + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap[ + "modifier" + ], + ), + ), + }), + phrase: z.object({ + kind: z.literal("sentence-structure"), + type: z.literal("phrase"), + id: z.uuid(), + startWordIndex: z.int().nonnegative(), + endWordIndex: z.int().nonnegative(), + sentenceElementName: z.nullable( + z.literal( + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap[ + "phrase" + ], + ), + ), + }), + clause: z.object({ + kind: z.literal("sentence-structure"), + type: z.literal("clause"), + id: z.uuid(), + startWordIndex: z.int().nonnegative(), + endWordIndex: z.int().nonnegative(), + sentenceElementName: z.nullable( + z.literal( + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap[ + "clause" + ], + ), + ), + }), + })[sentenceStructureRangeTypeOption], + ), + z.object({ + kind: z.literal(relationRangeTypeOption), + type: z.literal("relation"), + id: z.uuid(), + startWordIndex: z.int().nonnegative(), + endWordIndex: z.int().nonnegative(), + }), +]); +export type Range = z.infer; + +const RelationSchema = z.object({ + id: z.uuid(), + fromRangeId: z.uuid(), + toRangeId: z.uuid(), +}); +export type Relation = z.infer; + +export const coordinationChildTypeOptions = [ + "coordinating conjunction", + "correlative conjunction", + "conjunct", +] as const; +export type CoordinationChildType = + (typeof coordinationChildTypeOptions)[number]; + +const CoordinationChildSchema = z.object({ + type: z.literal(coordinationChildTypeOptions), + index: z.int().nonnegative(), + startWordIndex: z.int().nonnegative(), + endWordIndex: z.int().nonnegative(), +}); +export type CoordinationChild = z.infer; + +const CoordinationSchema = z.object({ + id: z.uuid(), + children: z.array(CoordinationChildSchema), +}); +export type Coordination = z.infer; + +export const SentenceStructureDataSchema = z + .object({ + text: z.string(), + words: z.array(WordSchema), + ranges: z.array(RangeSchema), + relations: z.array(RelationSchema), + coordinations: z.array(CoordinationSchema), + }) + .refine( + (sentenceStructureData) => + sentenceStructureData.words.every((word, index) => word.index === index), + { error: "単語のインデックスが0から始まる連続した整数ではありません。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.ranges.every( + (range) => + range.startWordIndex <= range.endWordIndex && + range.endWordIndex < sentenceStructureData.words.length, + ), + { error: "範囲を示す単語のインデックスが不正な値です。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.ranges.every((range) => + sentenceStructureData.ranges.every( + (otherRange) => + !( + range.id !== otherRange.id && + range.startWordIndex === otherRange.startWordIndex && + range.endWordIndex === otherRange.endWordIndex + ), + ), + ), + { + error: "開始位置と終了位置が同じ範囲が複数存在します。", + }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.ranges.every((range) => + sentenceStructureData.ranges.every( + (otherRange) => + range.id === otherRange.id || + otherRange.endWordIndex < range.startWordIndex || + (range.startWordIndex <= otherRange.startWordIndex && + otherRange.endWordIndex <= range.endWordIndex) || + (otherRange.startWordIndex <= range.startWordIndex && + range.endWordIndex <= otherRange.endWordIndex) || + range.endWordIndex < otherRange.startWordIndex, + ), + ), + { error: "範囲が部分的に重なっています。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.ranges + .filter((range) => range.kind === "relation") + .every((relationRange) => + sentenceStructureData.relations.some( + (relation) => + relation.fromRangeId === relationRange.id || + relation.toRangeId === relationRange.id, + ), + ), + { error: "範囲(関係)が関係の始点または終点として使われていません。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.relations.every( + (relation) => + sentenceStructureData.ranges.some( + (range) => range.id === relation.fromRangeId, + ) && + sentenceStructureData.ranges.some( + (range) => range.id === relation.toRangeId, + ), + ), + { error: "関係が存在しない範囲を参照しています。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.relations.every((relation) => + sentenceStructureData.relations.every( + (otherRelation) => + !( + relation.id !== otherRelation.id && + relation.fromRangeId === otherRelation.fromRangeId && + relation.toRangeId === otherRelation.toRangeId + ), + ), + ), + { + error: "同じ始点と終点を持つ関係が複数存在します。", + }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.coordinations.every((coordination) => + coordination.children.every((child, index) => child.index === index), + ), + { + error: + "並列構造の子要素のインデックスが0から始まる連続した整数ではありません。", + }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.coordinations.every( + (coordination) => 3 <= coordination.children.length, + ), + { error: "並列構造の子要素は3つ以上必要です。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.coordinations.every((coordination) => + coordination.children.every( + (child) => + child.startWordIndex <= child.endWordIndex && + child.endWordIndex < sentenceStructureData.words.length, + ), + ), + { error: "並列構造の子要素の単語のインデックスが不正な値です。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.coordinations.every((coordination) => { + for (let i = 1; i < coordination.children.length; i++) { + if ( + coordination.children[i - 1]!.endWordIndex + 1 !== + coordination.children[i]!.startWordIndex + ) { + return false; + } + } + return true; + }), + { error: "並列構造の子要素が連続していません。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.coordinations.every((coordination) => + coordination.children.every((child) => + sentenceStructureData.ranges.every( + (range) => + range.endWordIndex < child.startWordIndex || + (child.startWordIndex <= range.startWordIndex && + range.endWordIndex <= child.endWordIndex) || + (range.startWordIndex <= child.startWordIndex && + child.endWordIndex <= range.endWordIndex) || + child.endWordIndex < range.startWordIndex, + ), + ), + ), + { error: "並列構造の子要素が範囲と部分的に重なっています。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.coordinations.every((coordination) => + sentenceStructureData.coordinations.every((otherCoordination) => { + if (coordination.id === otherCoordination.id) return true; + const coordinationStart = coordination.children.at(0)!.startWordIndex; + const coordinationEnd = coordination.children.at(-1)!.endWordIndex; + const otherCoordinationStart = + otherCoordination.children.at(0)!.startWordIndex; + const otherCoordinationEnd = + otherCoordination.children.at(-1)!.endWordIndex; + return !( + coordinationStart === otherCoordinationStart && + coordinationEnd === otherCoordinationEnd + ); + }), + ), + { error: "開始位置と終了位置が同じ並列構造が複数存在します。" }, + ) + .refine( + (sentenceStructureData) => + sentenceStructureData.coordinations.every((coordination) => + sentenceStructureData.coordinations.every((otherCoordination) => { + if (coordination.id === otherCoordination.id) return true; + const coordinationStart = coordination.children.at(0)!.startWordIndex; + const coordinationEnd = coordination.children.at(-1)!.endWordIndex; + const otherCoordinationStart = + otherCoordination.children.at(0)!.startWordIndex; + const otherCoordinationEnd = + otherCoordination.children.at(-1)!.endWordIndex; + if ( + coordinationEnd - coordinationStart < + otherCoordinationEnd - otherCoordinationStart + ) + return true; + return ( + otherCoordinationEnd < coordinationStart || + coordination.children.some( + (child) => + child.startWordIndex <= otherCoordinationStart && + otherCoordinationEnd <= child.endWordIndex, + ) || + coordinationEnd < otherCoordinationStart + ); + }), + ), + { error: "並列構造が部分的に重なっています。" }, + ); +export type SentenceStructureData = z.infer; diff --git a/packages/sentence-structure-data/simplified-schema.ts b/packages/sentence-structure-data/simplified-schema.ts new file mode 100644 index 0000000..f7b3156 --- /dev/null +++ b/packages/sentence-structure-data/simplified-schema.ts @@ -0,0 +1,219 @@ +import * as z from "zod"; +import { + sentenceElementRangeTypeOptions, + sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap, + sentenceStructureRangeTypeOptions, + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap, +} from "./schema.js"; + +export const SimplifiedAnnotationDataSchema = z.object({ + ranges: z.array( + z + .union([ + ...sentenceElementRangeTypeOptions.map( + (sentenceElementRangeTypeOption) => + ({ + "core-sentence-element": z + .object({ + type: z.literal("文の主要素").describe("範囲の種類"), + index: z + .int() + .nonnegative() + .describe("範囲を識別するためのインデックス"), + startWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる先頭の単語のインデックス"), + endWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる末尾の単語のインデックス"), + sentenceElementName: z + .nullable( + z.literal( + sentenceElementRangeTypeToAllowedSentenceElementNameOptionsMap[ + "core-sentence-element" + ], + ), + ) + .describe("文の要素の名前"), + }) + .describe("文の主要素の範囲"), + })[sentenceElementRangeTypeOption], + ), + ...sentenceStructureRangeTypeOptions.map( + (sentenceStructureRangeTypeOption) => + ({ + modifier: z + .object({ + type: z.literal("修飾語").describe("範囲の種類"), + index: z + .int() + .nonnegative() + .describe("範囲を識別するためのインデックス"), + startWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる先頭の単語のインデックス"), + endWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる末尾の単語のインデックス"), + sentenceElementName: z + .nullable( + z.literal( + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap[ + "modifier" + ], + ), + ) + .describe("文の要素の名前"), + }) + .describe("修飾語の範囲"), + phrase: z + .object({ + type: z.literal("句").describe("範囲の種類"), + index: z + .int() + .nonnegative() + .describe("範囲を識別するためのインデックス"), + startWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる先頭の単語のインデックス"), + endWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる末尾の単語のインデックス"), + sentenceElementName: z + .nullable( + z.literal( + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap[ + "phrase" + ], + ), + ) + .describe("文の要素の名前"), + }) + .describe("句の範囲"), + clause: z + .object({ + type: z.literal("節").describe("範囲の種類"), + index: z + .int() + .nonnegative() + .describe("範囲を識別するためのインデックス"), + startWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる先頭の単語のインデックス"), + endWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる末尾の単語のインデックス"), + sentenceElementName: z + .nullable( + z.literal( + sentenceStructureRangeTypeToAllowedSentenceElementNameOptionsMap[ + "clause" + ], + ), + ) + .describe("文の要素の名前"), + }) + .describe("節の範囲"), + })[sentenceStructureRangeTypeOption], + ), + z + .object({ + type: z.literal("関係").describe("範囲の種類"), + index: z + .int() + .nonnegative() + .describe("範囲を識別するためのインデックス"), + startWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる先頭の単語のインデックス"), + endWordIndex: z + .int() + .nonnegative() + .describe("範囲に含まれる末尾の単語のインデックス"), + }) + .describe("関係の範囲"), + ]) + .describe("範囲"), + ), + relations: z.array( + z + .object({ + fromRangeIndex: z + .int() + .nonnegative() + .describe("関係の始点となる範囲のインデックス"), + toRangeIndex: z + .int() + .nonnegative() + .describe("関係の終点となる範囲のインデックス"), + }) + .describe("関係"), + ), + coordinations: z.array( + z + .object({ + children: z.array( + z + .object({ + type: z + .literal(["等位接続詞", "相関接続詞", "並列要素"]) + .describe("子要素の種類"), + startWordIndex: z + .int() + .nonnegative() + .describe("子要素に含まれる先頭の単語のインデックス"), + endWordIndex: z + .int() + .nonnegative() + .describe("子要素に含まれる末尾の単語のインデックス"), + }) + .describe("子要素"), + ), + }) + .describe("並列構造"), + ), +}); +export type SimplifiedAnnotationData = z.infer< + typeof SimplifiedAnnotationDataSchema +>; + +export const SimplifiedSentenceStructureDataSchema = + SimplifiedAnnotationDataSchema.extend({ + text: z.string(), + words: z.array( + z.object({ + index: z.int().nonnegative(), + text: z.string(), + }), + ), + }) + .refine( + (simplifiedSentenceStructureData) => + simplifiedSentenceStructureData.ranges + .sort((a, b) => a.index - b.index) + .every((range, index) => range.index === index), + { error: "範囲のインデックスが0から始まる連続した整数ではありません。" }, + ) + .refine( + (simplifiedSentenceStructureData) => + simplifiedSentenceStructureData.relations.every( + (relation) => + relation.fromRangeIndex < + simplifiedSentenceStructureData.ranges.length && + relation.toRangeIndex < + simplifiedSentenceStructureData.ranges.length, + ), + { error: "関係が存在しない範囲を参照しています。" }, + ); +export type SimplifiedSentenceStructureData = z.infer< + typeof SimplifiedSentenceStructureDataSchema +>; diff --git a/packages/sentence-structure-data/tokenize-text.ts b/packages/sentence-structure-data/tokenize-text.ts new file mode 100644 index 0000000..93725dc --- /dev/null +++ b/packages/sentence-structure-data/tokenize-text.ts @@ -0,0 +1,25 @@ +// import nlp from "compromise"; +import type { Word } from "./schema.js"; + +const segmenter = new Intl.Segmenter("en", { granularity: "word" }); +export function tokenizeText(text: string): Word[] { + if (text.trim() === "") return []; + + return [...segmenter.segment(text)] + .filter((segment) => segment.segment.trim() !== "") + .map((segment, index) => ({ + index: index, + text: segment.segment, + })); +} + +// export function tokenizeText(text: string): Word[] { +// const tokenizedText: string[] = nlp(text) +// .terms() +// .json() +// .map((term: { text: string }) => term.text); +// return tokenizedText.map((text, index) => ({ +// index: index, +// text: text, +// })); +// } diff --git a/packages/sentence-structure-data/tsconfig.json b/packages/sentence-structure-data/tsconfig.json new file mode 100644 index 0000000..d6a2b39 --- /dev/null +++ b/packages/sentence-structure-data/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/packages/sentence-structure-diagram-configurations/.gitignore b/packages/sentence-structure-diagram-configurations/.gitignore new file mode 100644 index 0000000..9b1c8b1 --- /dev/null +++ b/packages/sentence-structure-diagram-configurations/.gitignore @@ -0,0 +1 @@ +/dist diff --git a/packages/sentence-structure-diagram-configurations/default-configurations.ts b/packages/sentence-structure-diagram-configurations/default-configurations.ts new file mode 100644 index 0000000..ffef31a --- /dev/null +++ b/packages/sentence-structure-diagram-configurations/default-configurations.ts @@ -0,0 +1,26 @@ +import type { Configurations } from "./schema.js"; + +export const defaultConfigurations: Configurations = { + color: { + primaryColor: "#1976d2", + textColor: "#000000", + }, + sentenceStructureRangeTypeToBracketNameMap: { + modifier: "(parenthesis)", + phrase: "", + clause: "[square-bracket]", + }, + sentenceElementNameToSentenceElementSymbolMap: { + S: "S", + V: "V", + C: "C", + O: "O", + M: "M", + }, + sentenceElementPositionType: { + sentenceElementRangeSentenceElementPositionType: "bottom-center", + sentenceStructureRangeSentenceElementPositionType: "bottom-left", + }, + relationShapeType: "curved", + layoutMode: "structured", +}; diff --git a/packages/sentence-structure-diagram-configurations/format.ts b/packages/sentence-structure-diagram-configurations/format.ts new file mode 100644 index 0000000..b3877b8 --- /dev/null +++ b/packages/sentence-structure-diagram-configurations/format.ts @@ -0,0 +1,22 @@ +import * as z from "zod"; +import { XMLBuilder, XMLParser } from "fast-xml-parser"; +import { ConfigurationsSchema } from "./schema.js"; + +export const stringToConfigurations = z.codec( + z.string(), + ConfigurationsSchema, + { + decode: (string) => JSON.parse(string), + encode: (configurations) => JSON.stringify(configurations, null, 2), + }, +); + +export const xmlStringToConfigurations = z.codec( + z.string(), + ConfigurationsSchema, + { + decode: (xml) => new XMLParser().parse(xml), + encode: (configurations) => + new XMLBuilder({ format: true }).build(configurations), + }, +); diff --git a/packages/sentence-structure-diagram-configurations/index.ts b/packages/sentence-structure-diagram-configurations/index.ts new file mode 100644 index 0000000..6459ab8 --- /dev/null +++ b/packages/sentence-structure-diagram-configurations/index.ts @@ -0,0 +1,9 @@ +export type { + BracketName, + SentenceElementPositionType, + RelationShapeType, + LayoutMode, + Configurations, +} from "./schema.js"; +export { defaultConfigurations } from "./default-configurations.js"; +export { stringToConfigurations, xmlStringToConfigurations } from "./format.js"; diff --git a/packages/sentence-structure-diagram-configurations/package.json b/packages/sentence-structure-diagram-configurations/package.json new file mode 100644 index 0000000..188cf55 --- /dev/null +++ b/packages/sentence-structure-diagram-configurations/package.json @@ -0,0 +1,19 @@ +{ + "name": "@sentence-structure-diagram-app/sentence-structure-diagram-configurations", + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "clean": "rm -r dist" + }, + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "fast-xml-parser": "^5.3.3", + "zod": "^4.2.1" + }, + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/packages/sentence-structure-diagram-configurations/schema.ts b/packages/sentence-structure-diagram-configurations/schema.ts new file mode 100644 index 0000000..5de0bca --- /dev/null +++ b/packages/sentence-structure-diagram-configurations/schema.ts @@ -0,0 +1,51 @@ +import * as z from "zod"; +import { + sentenceElementNameOptions, + sentenceStructureRangeTypeOptions, +} from "@sentence-structure-diagram-app/sentence-structure-data"; + +const BracketNameSchema = z.literal([ + "(parenthesis)", + "", + "{curly-bracket}", + "[square-bracket]", +]); +export type BracketName = z.infer; + +const SentenceElementPositionTypeSchema = z.literal([ + "bottom-center", + "bottom-left", +]); +export type SentenceElementPositionType = z.infer< + typeof SentenceElementPositionTypeSchema +>; + +const RelationShapeTypeSchema = z.literal(["curved", "right-angle"]); +export type RelationShapeType = z.infer; + +const LayoutModeSchema = z.literal(["linear", "structured"]); +export type LayoutMode = z.infer; + +export const ConfigurationsSchema = z.object({ + color: z.object({ + primaryColor: z.string(), + textColor: z.string(), + }), + sentenceStructureRangeTypeToBracketNameMap: z.record( + z.literal(sentenceStructureRangeTypeOptions), + BracketNameSchema, + ), + sentenceElementNameToSentenceElementSymbolMap: z.record( + z.literal(sentenceElementNameOptions), + z.string(), + ), + sentenceElementPositionType: z.object({ + sentenceElementRangeSentenceElementPositionType: + SentenceElementPositionTypeSchema, + sentenceStructureRangeSentenceElementPositionType: + SentenceElementPositionTypeSchema, + }), + relationShapeType: RelationShapeTypeSchema, + layoutMode: LayoutModeSchema, +}); +export type Configurations = z.infer; diff --git a/packages/sentence-structure-diagram-configurations/tsconfig.json b/packages/sentence-structure-diagram-configurations/tsconfig.json new file mode 100644 index 0000000..d6a2b39 --- /dev/null +++ b/packages/sentence-structure-diagram-configurations/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/packages/sentence-structure-diagram-data/.gitignore b/packages/sentence-structure-diagram-data/.gitignore new file mode 100644 index 0000000..9b1c8b1 --- /dev/null +++ b/packages/sentence-structure-diagram-data/.gitignore @@ -0,0 +1 @@ +/dist diff --git a/packages/sentence-structure-diagram-data/extract-position.ts b/packages/sentence-structure-diagram-data/extract-position.ts new file mode 100644 index 0000000..abf1e79 --- /dev/null +++ b/packages/sentence-structure-diagram-data/extract-position.ts @@ -0,0 +1,74 @@ +import type { + SentenceStructureDiagramNode, + SentenceStructureDiagramTree, +} from "@sentence-structure-diagram-app/sentence-structure-diagram-tree"; + +type WordPosition = { + wordIndex: number; + start: number; + end: number; + top: number; + bottom: number; +}; + +export function extractWordPositions( + treePosition: SentenceStructureDiagramTree, +): WordPosition[] { + const wordPositions: WordPosition[] = []; + + function traverse(node: SentenceStructureDiagramNode): void { + if (!("children" in node)) { + wordPositions.push({ + wordIndex: node.word.index, + start: node.position.start, + end: node.position.end, + top: node.position.top, + bottom: node.position.bottom, + }); + return; + } + for (const child of node.children) { + traverse(child); + } + } + + traverse(treePosition); + + return wordPositions.sort((a, b) => a.wordIndex - b.wordIndex); +} + +type SpanPosition = { + start: number; + end: number; + top: number; + bottom: number; +}[]; + +export function extractSpanPosition( + wordPositions: WordPosition[], + startWordIndex: number, + endWordIndex: number, +): SpanPosition { + const wordPositionsInRange = wordPositions.filter( + (wordPosition) => + startWordIndex <= wordPosition.wordIndex && + wordPosition.wordIndex <= endWordIndex, + ); + + const rangePosition: SpanPosition = []; + + for (const wordPosition of wordPositionsInRange) { + if (wordPosition.bottom === rangePosition.at(-1)?.bottom) { + rangePosition.at(-1)!.end = wordPosition.end; + } else { + rangePosition.push({ + start: wordPosition.start, + end: wordPosition.end, + top: wordPosition.top, + bottom: wordPosition.bottom, + }); + } + } + + return rangePosition; +} diff --git a/packages/sentence-structure-diagram-data/generate.ts b/packages/sentence-structure-diagram-data/generate.ts new file mode 100644 index 0000000..257ffd1 --- /dev/null +++ b/packages/sentence-structure-diagram-data/generate.ts @@ -0,0 +1,172 @@ +import { + findRangeById, + type SentenceStructureData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import type { Configurations } from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; +import { createTree } from "@sentence-structure-diagram-app/sentence-structure-tree"; +import { createSentenceStructureDiagramTree } from "@sentence-structure-diagram-app/sentence-structure-diagram-tree"; +import type { SentenceStructureDiagramData } from "./types.js"; +import { + extractSpanPosition, + extractWordPositions, +} from "./extract-position.js"; +import { resolveConfigurations } from "./resolve-configurations.js"; + +export function convertSentenceStructureDataToSentenceStructureDiagramData( + sentenceStructureData: SentenceStructureData, + maxWidth: number, + measureTextWidth: (text: string) => number, + customConfigurations: Partial, +): SentenceStructureDiagramData { + const resolvedConfigurations = resolveConfigurations(customConfigurations); + + const tree = createTree(sentenceStructureData); + const treePosition = createSentenceStructureDiagramTree( + tree, + maxWidth, + measureTextWidth, + resolvedConfigurations.layoutMode, + ); + const wordPositions = extractWordPositions(treePosition); + + return { + position: { + left: treePosition.position.start, + right: treePosition.position.end, + top: treePosition.position.top, + bottom: treePosition.position.bottom, + }, + color: { + primaryColor: resolvedConfigurations.color.primaryColor, + textColor: resolvedConfigurations.color.textColor, + }, + words: sentenceStructureData.words.map((word) => ({ + index: word.index, + text: word.text, + openingBrackets: sentenceStructureData.ranges + .filter((range) => range.kind === "sentence-structure") + .filter((range) => range.startWordIndex === word.index) + .sort((a, b) => b.endWordIndex - a.endWordIndex) + .map( + (range) => + resolvedConfigurations.sentenceStructureRangeTypeToBracketsMap[ + range.type + ].openingBracket, + ), + closingBrackets: sentenceStructureData.ranges + .filter((range) => range.kind === "sentence-structure") + .filter((range) => range.endWordIndex === word.index) + .sort((a, b) => b.startWordIndex - a.startWordIndex) + .map( + (range) => + resolvedConfigurations.sentenceStructureRangeTypeToBracketsMap[ + range.type + ].closingBracket, + ), + position: { + left: wordPositions[word.index]!.start, + right: wordPositions[word.index]!.end, + top: wordPositions[word.index]!.top, + bottom: wordPositions[word.index]!.bottom, + }, + })), + underlines: sentenceStructureData.ranges + .filter((range) => range.type === "core-sentence-element") + .map((range) => { + const rangePosition = extractSpanPosition( + wordPositions, + range.startWordIndex, + range.endWordIndex, + ); + return { + rangeId: range.id, + position: rangePosition.map((position) => ({ + start: position.start, + end: position.end, + bottom: position.bottom + 4, + })), + }; + }), + sentenceElements: sentenceStructureData.ranges + .filter((range) => range.kind !== "relation") + .map((range) => { + const rangePosition = extractSpanPosition( + wordPositions, + range.startWordIndex, + range.endWordIndex, + ); + return { + rangeId: range.id, + symbol: range.sentenceElementName + ? resolvedConfigurations + .sentenceElementNameToSentenceElementSymbolMap[ + range.sentenceElementName + ] + : null, + position: + range.kind === "sentence-element" + ? resolvedConfigurations.sentenceElementPosition.determineSentenceElementRangeSentenceElementPosition( + rangePosition, + ) + : resolvedConfigurations.sentenceElementPosition.determineSentenceStructureRangeSentenceElementPosition( + rangePosition, + ), + }; + }), + relations: sentenceStructureData.relations.map((relation) => { + const fromRange = findRangeById(sentenceStructureData, { + rangeId: relation.fromRangeId, + }); + const toRange = findRangeById(sentenceStructureData, { + rangeId: relation.toRangeId, + }); + if (!fromRange || !toRange) { + throw new Error( + `Relation ${relation.id} has invalid range references.`, + ); + } + + const fromRangePosition = extractSpanPosition( + wordPositions, + fromRange.startWordIndex, + fromRange.endWordIndex, + ); + const toRangePosition = extractSpanPosition( + wordPositions, + toRange.startWordIndex, + toRange.endWordIndex, + ); + + return { + relationId: relation.id, + svgPathData: resolvedConfigurations.determineRelationSvgPathData( + fromRangePosition, + toRangePosition, + ), + }; + }), + coordinations: sentenceStructureData.coordinations.map((coordination) => { + const coordinationPosition = { + position: extractSpanPosition( + wordPositions, + coordination.children.at(0)!.startWordIndex, + coordination.children.at(-1)!.endWordIndex, + ), + childrenPositions: coordination.children.map((child) => + extractSpanPosition( + wordPositions, + child.startWordIndex, + child.endWordIndex, + ), + ), + }; + return { + coordinationId: coordination.id, + svgPathData: + resolvedConfigurations.determineCoordinationSvgPathData( + coordinationPosition, + ), + }; + }), + }; +} diff --git a/packages/sentence-structure-diagram-data/index.ts b/packages/sentence-structure-diagram-data/index.ts new file mode 100644 index 0000000..0c08cf0 --- /dev/null +++ b/packages/sentence-structure-diagram-data/index.ts @@ -0,0 +1,2 @@ +export { convertSentenceStructureDataToSentenceStructureDiagramData } from "./generate.js"; +export type { SentenceStructureDiagramData } from "./types.js"; diff --git a/packages/sentence-structure-diagram-data/package.json b/packages/sentence-structure-diagram-data/package.json new file mode 100644 index 0000000..c5da8cc --- /dev/null +++ b/packages/sentence-structure-diagram-data/package.json @@ -0,0 +1,21 @@ +{ + "name": "@sentence-structure-diagram-app/sentence-structure-diagram-data", + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "clean": "rm -r dist" + }, + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-configurations": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-tree": "^0.1.0", + "fast-xml-parser": "^5.3.2", + "zod": "^4.1.13" + }, + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/packages/sentence-structure-diagram-data/resolve-configurations.ts b/packages/sentence-structure-diagram-data/resolve-configurations.ts new file mode 100644 index 0000000..dfa3de3 --- /dev/null +++ b/packages/sentence-structure-diagram-data/resolve-configurations.ts @@ -0,0 +1,300 @@ +import type { + SentenceElementName, + SentenceStructureRangeType, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import { + defaultConfigurations, + type BracketName, + type Configurations, + type LayoutMode, + type RelationShapeType, + type SentenceElementPositionType, +} from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; + +type SpanPosition = { + start: number; + end: number; + top: number; + bottom: number; +}[]; + +type RangePosition = SpanPosition; + +type CoordinationPosition = { + position: SpanPosition; + childrenPositions: SpanPosition[]; +}; + +type ResolvedConfigurations = { + color: { + primaryColor: string; + textColor: string; + }; + sentenceStructureRangeTypeToBracketsMap: Record< + SentenceStructureRangeType, + { openingBracket: string; closingBracket: string } + >; + sentenceElementNameToSentenceElementSymbolMap: Record< + SentenceElementName, + string + >; + sentenceElementPosition: { + determineSentenceElementRangeSentenceElementPosition: ( + rangePosition: RangePosition, + ) => { x: number; y: number }; + determineSentenceStructureRangeSentenceElementPosition: ( + rangePosition: RangePosition, + ) => { x: number; y: number }; + }; + determineRelationSvgPathData: ( + fromRangePosition: RangePosition, + toRangePosition: RangePosition, + ) => string; + determineCoordinationSvgPathData: ( + coordinationPosition: CoordinationPosition, + ) => string; + layoutMode: LayoutMode; +}; + +function convertBracketNameToBrackets(bracketName: BracketName) { + switch (bracketName) { + case "(parenthesis)": + return { openingBracket: "(", closingBracket: ")" }; + case "": + return { openingBracket: "<", closingBracket: ">" }; + case "{curly-bracket}": + return { openingBracket: "{", closingBracket: "}" }; + case "[square-bracket]": + return { openingBracket: "[", closingBracket: "]" }; + } +} + +function determineSentenceElementPosition( + sentenceElementPositionType: SentenceElementPositionType, + rangePosition: RangePosition, +) { + switch (sentenceElementPositionType) { + case "bottom-center": + return { + x: (rangePosition[0]!.start + rangePosition[0]!.end) / 2, + y: rangePosition[0]!.bottom + 8, + }; + case "bottom-left": + return { + x: rangePosition[0]!.start - 4, + y: rangePosition[0]!.bottom + 8, + }; + } +} + +function determineRelationSvgPathData( + relationShapeType: RelationShapeType, + fromRangePosition: RangePosition, + toRangePosition: RangePosition, +) { + const fromPoint = { + x: + fromRangePosition[0]!.start + + (fromRangePosition[0]!.end - fromRangePosition[0]!.start) / 2, + y: fromRangePosition[0]!.top, + }; + const toPoint = { + x: + toRangePosition[0]!.start + + (toRangePosition[0]!.end - toRangePosition[0]!.start) / 2, + y: toRangePosition[0]!.top, + }; + + const height = 40; + + const curveTopY = Math.min(fromPoint.y, toPoint.y) - height; + const arrowSize = 4; + const arrowPosition = { + left: toPoint.x - arrowSize, + right: toPoint.x + arrowSize, + top: toPoint.y - arrowSize, + }; + const curveSvgPathData = [ + // 曲線 + `M ${fromPoint.x},${fromPoint.y}`, + `C ${fromPoint.x},${curveTopY} ${toPoint.x},${curveTopY} ${toPoint.x},${toPoint.y}`, + // 矢印 + `M ${arrowPosition.left},${arrowPosition.top}`, + `L ${toPoint.x},${toPoint.y}`, + `L ${arrowPosition.right},${arrowPosition.top}`, + ].join(" "); + + const straightSvgPathData = [ + // 直線 + `M ${fromPoint.x},${fromPoint.y}`, + `L ${fromPoint.x},${fromPoint.y - height / 2}`, + `L ${toPoint.x},${toPoint.y - height / 2}`, + `L ${toPoint.x},${toPoint.y}`, + // 矢印 + `M ${arrowPosition.left},${arrowPosition.top}`, + `L ${toPoint.x},${toPoint.y}`, + `L ${arrowPosition.right},${arrowPosition.top}`, + ].join(" "); + + switch (relationShapeType) { + case "curved": + return curveSvgPathData; + case "right-angle": + if (fromPoint.y === toPoint.y) { + return straightSvgPathData; + } else { + return curveSvgPathData; + } + } +} + +function determineCoordinationSvgPathData( + layoutMode: LayoutMode, + coordinationPosition: CoordinationPosition, +) { + switch (layoutMode) { + case "linear": { + const verticalLines = coordinationPosition.childrenPositions.map( + (position) => ({ + start: (position.at(0)!.start + position.at(0)!.end) / 2, + top: position.at(0)!.top - 20, + bottom: position.at(0)!.top, + }), + ); + const overLines = coordinationPosition.position.map( + (position, index) => ({ + start: + index === 0 + ? (coordinationPosition.childrenPositions.at(0)!.at(0)!.start + + coordinationPosition.childrenPositions.at(0)!.at(0)!.end) / + 2 + : position.start, + end: + index === coordinationPosition.position.length - 1 + ? (coordinationPosition.childrenPositions.at(-1)!.at(-1)!.start + + coordinationPosition.childrenPositions.at(-1)!.at(-1)!.end) / + 2 + : position.end, + top: position.top - 20, + }), + ); + return ( + verticalLines + .map( + (verticalLine) => + `M ${verticalLine.start} ${verticalLine.top} L ${verticalLine.start} ${verticalLine.bottom}`, + ) + .join(" ") + + " " + + overLines + .map( + (overLine) => + `M ${overLine.start} ${overLine.top} L ${overLine.end} ${overLine.top}`, + ) + .join(" ") + ); + } + case "structured": + const verticalLine = { + start: coordinationPosition.position.at(0)!.start - 10, + top: + (coordinationPosition.position.at(0)!.top + + coordinationPosition.position.at(0)!.bottom) / + 2, + bottom: + (coordinationPosition.position.at(-1)!.top + + coordinationPosition.position.at(-1)!.bottom) / + 2 + + 8, + }; + const topHorizontalLine = { + start: verticalLine.start, + end: verticalLine.start + 10, + top: verticalLine.top, + }; + const bottomHorizontalLine = { + start: verticalLine.start, + end: verticalLine.start + 10, + top: verticalLine.bottom, + }; + return [ + // 縦線 + `M ${verticalLine.start} ${verticalLine.top} L ${verticalLine.start} ${verticalLine.bottom}`, + // 上の横線 + `M ${topHorizontalLine.start} ${topHorizontalLine.top} L ${topHorizontalLine.end} ${topHorizontalLine.top}`, + // 下の横線 + `M ${bottomHorizontalLine.start} ${bottomHorizontalLine.top} L ${bottomHorizontalLine.end} ${bottomHorizontalLine.top}`, + ].join(" "); + } +} + +export function resolveConfigurations( + customConfigurations: Partial, +): ResolvedConfigurations { + const configurations: Configurations = { + color: customConfigurations.color + ? customConfigurations.color + : defaultConfigurations.color, + sentenceStructureRangeTypeToBracketNameMap: + customConfigurations.sentenceStructureRangeTypeToBracketNameMap + ? customConfigurations.sentenceStructureRangeTypeToBracketNameMap + : defaultConfigurations.sentenceStructureRangeTypeToBracketNameMap, + sentenceElementNameToSentenceElementSymbolMap: + customConfigurations.sentenceElementNameToSentenceElementSymbolMap + ? customConfigurations.sentenceElementNameToSentenceElementSymbolMap + : defaultConfigurations.sentenceElementNameToSentenceElementSymbolMap, + sentenceElementPositionType: + customConfigurations.sentenceElementPositionType + ? customConfigurations.sentenceElementPositionType + : defaultConfigurations.sentenceElementPositionType, + relationShapeType: customConfigurations.relationShapeType + ? customConfigurations.relationShapeType + : defaultConfigurations.relationShapeType, + layoutMode: customConfigurations.layoutMode + ? customConfigurations.layoutMode + : defaultConfigurations.layoutMode, + }; + + return { + color: configurations.color, + sentenceStructureRangeTypeToBracketsMap: { + modifier: convertBracketNameToBrackets( + configurations.sentenceStructureRangeTypeToBracketNameMap.modifier, + ), + phrase: convertBracketNameToBrackets( + configurations.sentenceStructureRangeTypeToBracketNameMap.phrase, + ), + clause: convertBracketNameToBrackets( + configurations.sentenceStructureRangeTypeToBracketNameMap.clause, + ), + }, + sentenceElementNameToSentenceElementSymbolMap: + configurations.sentenceElementNameToSentenceElementSymbolMap, + sentenceElementPosition: { + determineSentenceElementRangeSentenceElementPosition: (rangePosition) => + determineSentenceElementPosition( + configurations.sentenceElementPositionType + .sentenceElementRangeSentenceElementPositionType, + rangePosition, + ), + determineSentenceStructureRangeSentenceElementPosition: (rangePosition) => + determineSentenceElementPosition( + configurations.sentenceElementPositionType + .sentenceStructureRangeSentenceElementPositionType, + rangePosition, + ), + }, + determineRelationSvgPathData: (fromRangePosition, toRangePosition) => + determineRelationSvgPathData( + configurations.relationShapeType, + fromRangePosition, + toRangePosition, + ), + determineCoordinationSvgPathData: (coordinationPosition) => + determineCoordinationSvgPathData( + configurations.layoutMode, + coordinationPosition, + ), + layoutMode: configurations.layoutMode, + }; +} diff --git a/packages/sentence-structure-diagram-data/tsconfig.json b/packages/sentence-structure-diagram-data/tsconfig.json new file mode 100644 index 0000000..d6a2b39 --- /dev/null +++ b/packages/sentence-structure-diagram-data/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/packages/sentence-structure-diagram-data/types.ts b/packages/sentence-structure-diagram-data/types.ts new file mode 100644 index 0000000..ab65ba0 --- /dev/null +++ b/packages/sentence-structure-diagram-data/types.ts @@ -0,0 +1,48 @@ +export type SentenceStructureDiagramData = { + position: { + left: number; + right: number; + top: number; + bottom: number; + }; + color: { + primaryColor: string; + textColor: string; + }; + words: { + index: number; + text: string; + openingBrackets: string[]; + closingBrackets: string[]; + position: { + left: number; + right: number; + top: number; + bottom: number; + }; + }[]; + underlines: { + rangeId: string; + position: { + start: number; + end: number; + bottom: number; + }[]; + }[]; + sentenceElements: { + rangeId: string; + symbol: string | null; + position: { + x: number; + y: number; + }; + }[]; + relations: { + relationId: string; + svgPathData: string; + }[]; + coordinations: { + coordinationId: string; + svgPathData: string; + }[]; +}; diff --git a/packages/sentence-structure-diagram-svg/.gitignore b/packages/sentence-structure-diagram-svg/.gitignore new file mode 100644 index 0000000..9b1c8b1 --- /dev/null +++ b/packages/sentence-structure-diagram-svg/.gitignore @@ -0,0 +1 @@ +/dist diff --git a/packages/sentence-structure-diagram-svg/SentenceStructureDiagram.tsx b/packages/sentence-structure-diagram-svg/SentenceStructureDiagram.tsx new file mode 100644 index 0000000..1508805 --- /dev/null +++ b/packages/sentence-structure-diagram-svg/SentenceStructureDiagram.tsx @@ -0,0 +1,142 @@ +import { Fragment } from "react"; +import { + sentenceStructureDataToXMLString, + type SentenceStructureData, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import { + xmlStringToConfigurations, + type Configurations, +} from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; +import { convertSentenceStructureDataToSentenceStructureDiagramData } from "@sentence-structure-diagram-app/sentence-structure-diagram-data"; + +type SentenceStructureDiagramProps = { + sentenceStructureData: SentenceStructureData; + maxWidth: number; + measureTextWidth: (text: string) => number; + configurations: Configurations; +}; + +export default function SentenceStructureDiagram( + props: SentenceStructureDiagramProps, +) { + const sentenceStructureDiagramData = + convertSentenceStructureDataToSentenceStructureDiagramData( + props.sentenceStructureData, + props.maxWidth, + props.measureTextWidth, + props.configurations, + ); + return ( + + + ${sentenceStructureDataToXMLString(props.sentenceStructureData)} + + + ${xmlStringToConfigurations.encode(props.configurations)} + +`, + }} + > + {/* 単語と括弧類 */} + {sentenceStructureDiagramData.words.map((word) => ( + + {word.openingBrackets.length > 0 && ( + + {word.openingBrackets.join("")} + + )} + + {word.text} + + {word.closingBrackets.length > 0 && ( + + {word.closingBrackets.join("")} + + )} + + ))} + {/* 下線 */} + {sentenceStructureDiagramData.underlines.map((underline) => + underline.position.map((position, index) => ( + + )), + )} + {/* 文の要素の記号 */} + {sentenceStructureDiagramData.sentenceElements.map( + (sentenceElement) => + sentenceElement.symbol && ( + + {sentenceElement.symbol} + + ), + )} + {/* 矢印 */} + {sentenceStructureDiagramData.relations.map((relation) => ( + + ))} + {/* 並列 */} + {sentenceStructureDiagramData.coordinations.map((coordination) => ( + + ))} + + ); +} diff --git a/packages/sentence-structure-diagram-svg/generate.ts b/packages/sentence-structure-diagram-svg/generate.ts new file mode 100644 index 0000000..4528cb0 --- /dev/null +++ b/packages/sentence-structure-diagram-svg/generate.ts @@ -0,0 +1,28 @@ +import ReactDOMServer from "react-dom/server"; +// import prettier from "prettier/standalone"; +// import prettierPluginHtml from "prettier/plugins/html"; +import type { SentenceStructureData } from "@sentence-structure-diagram-app/sentence-structure-data"; +import type { Configurations } from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; +import SentenceStructureDiagram from "./SentenceStructureDiagram.js"; + +export function generateSvgString( + sentenceStructureData: SentenceStructureData, + maxWidth: number, + measureTextWidth: (text: string) => number, + configurations: Configurations, +): string { + // return await prettier.format( + return ReactDOMServer.renderToStaticMarkup( + SentenceStructureDiagram({ + sentenceStructureData, + maxWidth, + measureTextWidth, + configurations, + }), + ); + // { + // parser: "html", + // plugins: [prettierPluginHtml], + // }, + // ); +} diff --git a/packages/sentence-structure-diagram-svg/index.ts b/packages/sentence-structure-diagram-svg/index.ts new file mode 100644 index 0000000..6619bc8 --- /dev/null +++ b/packages/sentence-structure-diagram-svg/index.ts @@ -0,0 +1 @@ +export { generateSvgString } from "./generate.js"; diff --git a/packages/sentence-structure-diagram-svg/package.json b/packages/sentence-structure-diagram-svg/package.json new file mode 100644 index 0000000..2012eda --- /dev/null +++ b/packages/sentence-structure-diagram-svg/package.json @@ -0,0 +1,22 @@ +{ + "name": "@sentence-structure-diagram-app/sentence-structure-diagram-svg", + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "clean": "rm -r dist" + }, + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-configurations": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-data": "^0.1.0", + "prettier": "^3.7.4", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/packages/sentence-structure-diagram-svg/tsconfig.json b/packages/sentence-structure-diagram-svg/tsconfig.json new file mode 100644 index 0000000..d6a2b39 --- /dev/null +++ b/packages/sentence-structure-diagram-svg/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/packages/sentence-structure-diagram-tree/.gitignore b/packages/sentence-structure-diagram-tree/.gitignore new file mode 100644 index 0000000..9b1c8b1 --- /dev/null +++ b/packages/sentence-structure-diagram-tree/.gitignore @@ -0,0 +1 @@ +/dist diff --git a/packages/sentence-structure-diagram-tree/constants.ts b/packages/sentence-structure-diagram-tree/constants.ts new file mode 100644 index 0000000..d2990c9 --- /dev/null +++ b/packages/sentence-structure-diagram-tree/constants.ts @@ -0,0 +1,4 @@ +export const lineHeight = 16; +export const lineSpacing = 48; +export const wordSpacing = 32; +export const padding = 48; diff --git a/packages/sentence-structure-diagram-tree/create-linear-sentence-structure-diagram-tree.ts b/packages/sentence-structure-diagram-tree/create-linear-sentence-structure-diagram-tree.ts new file mode 100644 index 0000000..18c4706 --- /dev/null +++ b/packages/sentence-structure-diagram-tree/create-linear-sentence-structure-diagram-tree.ts @@ -0,0 +1,268 @@ +import type { + SentenceStructureCoordinationChildNode, + SentenceStructureCoordinationNode, + SentenceStructureNode, + SentenceStructureRangeNode, + SentenceStructureTree, + SentenceStructureWordNode, +} from "@sentence-structure-diagram-app/sentence-structure-tree"; +import type { + SentenceStructureDiagramCoordinationChildNode, + SentenceStructureDiagramCoordinationNode, + SentenceStructureDiagramNode, + SentenceStructureDiagramTree, + SentenceStructureDiagramRangeNode, + SentenceStructureDiagramWordNode, +} from "./types.js"; +import { lineHeight, lineSpacing, padding, wordSpacing } from "./constants.js"; + +type Input = { + sentenceStructureNode: T; + nextNodeStartPosition: { + start: number; + top: number; + }; + nextLineStartPosition: { + start: number; + top: number; + }; + maxWidth: number; + measureTextWidth: (text: string) => number; +}; + +type Result = { + sentenceStructureDiagramNode: T; + nextNodeStartPosition: { + start: number; + top: number; + }; + nextLineStartPosition: { + start: number; + top: number; + }; +}; + +function createSentenceStructureDiagramWordNode( + input: Input, +): Result { + let nextNodeStartPosition = { ...input.nextNodeStartPosition }; + let nextLineStartPosition = { ...input.nextLineStartPosition }; + if ( + input.maxWidth < + input.nextNodeStartPosition.start + + input.measureTextWidth(input.sentenceStructureNode.word.text) + + padding + ) { + nextNodeStartPosition = { ...input.nextLineStartPosition }; + nextLineStartPosition.top += lineHeight + lineSpacing; + } + return { + sentenceStructureDiagramNode: { + word: input.sentenceStructureNode.word, + position: { + start: nextNodeStartPosition.start, + end: + nextNodeStartPosition.start + + input.measureTextWidth(input.sentenceStructureNode.word.text), + top: nextNodeStartPosition.top, + bottom: nextNodeStartPosition.top + lineHeight, + }, + }, + nextNodeStartPosition: { + start: + nextNodeStartPosition.start + + input.measureTextWidth(input.sentenceStructureNode.word.text) + + wordSpacing, + top: nextNodeStartPosition.top, + }, + nextLineStartPosition, + }; +} + +function createSentenceStructureDiagramRangeNode( + input: Input, +): Result { + let nextNodeStartPosition = { ...input.nextNodeStartPosition }; + let nextLineStartPosition = { ...input.nextLineStartPosition }; + const children: SentenceStructureDiagramRangeNode["children"] = []; + for (const child of input.sentenceStructureNode.children) { + const result = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }) + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }) + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }); + children.push(result.sentenceStructureDiagramNode); + nextNodeStartPosition = { ...result.nextNodeStartPosition }; + nextLineStartPosition = { ...result.nextLineStartPosition }; + } + + return { + sentenceStructureDiagramNode: { + range: input.sentenceStructureNode.range, + position: { + end: nextNodeStartPosition.start - wordSpacing, + top: input.nextNodeStartPosition.top, + bottom: nextLineStartPosition.top - lineSpacing, + }, + children: children, + }, + nextNodeStartPosition, + nextLineStartPosition, + }; +} + +function createSentenceStructureDiagramCoordinationChildNode( + input: Input, +): Result { + let nextNodeStartPosition = { ...input.nextNodeStartPosition }; + let nextLineStartPosition = { ...input.nextLineStartPosition }; + const children: SentenceStructureDiagramRangeNode["children"] = []; + for (const child of input.sentenceStructureNode.children) { + const result = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }) + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }) + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }); + children.push(result.sentenceStructureDiagramNode); + nextNodeStartPosition = { ...result.nextNodeStartPosition }; + nextLineStartPosition = { ...result.nextLineStartPosition }; + } + + return { + sentenceStructureDiagramNode: { + coordinationChild: input.sentenceStructureNode.coordinationChild, + position: { + end: nextNodeStartPosition.start - wordSpacing, + top: input.nextNodeStartPosition.top, + bottom: nextLineStartPosition.top - lineSpacing, + }, + children: children, + }, + nextNodeStartPosition, + nextLineStartPosition, + }; +} + +function createSentenceStructureDiagramCoordinationNode( + input: Input, +): Result { + let nextNodeStartPosition = { ...input.nextNodeStartPosition }; + let nextLineStartPosition = { ...input.nextLineStartPosition }; + const children: SentenceStructureDiagramCoordinationNode["children"] = []; + for (const child of input.sentenceStructureNode.children) { + const result = createSentenceStructureDiagramCoordinationChildNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }); + children.push(result.sentenceStructureDiagramNode); + nextNodeStartPosition = { ...result.nextNodeStartPosition }; + nextLineStartPosition = { ...result.nextLineStartPosition }; + } + + return { + sentenceStructureDiagramNode: { + coordination: input.sentenceStructureNode.coordination, + position: { + end: nextNodeStartPosition.start - wordSpacing, + top: input.nextNodeStartPosition.top, + bottom: nextLineStartPosition.top - lineSpacing, + }, + children, + }, + nextNodeStartPosition, + nextLineStartPosition, + }; +} + +export function createLinearSentenceStructureDiagramTree( + sentenceStructureTree: SentenceStructureTree, + maxWidth: number, + measureTextWidth: (text: string) => number, +): SentenceStructureDiagramTree { + let nextNodeStartPosition = { start: padding, top: padding }; + let nextLineStartPosition = { + start: padding, + top: padding + lineHeight + lineSpacing, + }; + const children: SentenceStructureDiagramTree["children"] = []; + for (const child of sentenceStructureTree.children) { + const result = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth, + measureTextWidth, + }) + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth, + measureTextWidth, + }) + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth, + measureTextWidth, + }); + children.push(result.sentenceStructureDiagramNode); + nextNodeStartPosition = { ...result.nextNodeStartPosition }; + nextLineStartPosition = { ...result.nextLineStartPosition }; + } + + return { + position: { + start: 0, + end: maxWidth, + top: 0, + bottom: nextLineStartPosition.top - lineSpacing + padding, + }, + children: children, + }; +} diff --git a/packages/sentence-structure-diagram-tree/create-structured-sentence-structure-diagram-tree.ts b/packages/sentence-structure-diagram-tree/create-structured-sentence-structure-diagram-tree.ts new file mode 100644 index 0000000..55b2f81 --- /dev/null +++ b/packages/sentence-structure-diagram-tree/create-structured-sentence-structure-diagram-tree.ts @@ -0,0 +1,382 @@ +import type { + SentenceStructureCoordinationChildNode, + SentenceStructureCoordinationNode, + SentenceStructureNode, + SentenceStructureRangeNode, + SentenceStructureTree, + SentenceStructureWordNode, +} from "@sentence-structure-diagram-app/sentence-structure-tree"; +import type { + SentenceStructureDiagramCoordinationChildNode, + SentenceStructureDiagramCoordinationNode, + SentenceStructureDiagramNode, + SentenceStructureDiagramTree, + SentenceStructureDiagramRangeNode, + SentenceStructureDiagramWordNode, +} from "./types.js"; +import { lineHeight, lineSpacing, padding, wordSpacing } from "./constants.js"; + +type Input = { + sentenceStructureNode: T; + nextNodeStartPosition: { + start: number; + top: number; + }; + nextLineStartPosition: { + start: number; + top: number; + }; + maxWidth: number; + measureTextWidth: (text: string) => number; +}; + +type Result = { + sentenceStructureDiagramNode: T; + nextNodeStartPosition: { + start: number; + top: number; + }; + nextLineStartPosition: { + start: number; + top: number; + }; +}; + +function createSentenceStructureDiagramWordNode( + input: Input, +): Result { + return { + sentenceStructureDiagramNode: { + word: input.sentenceStructureNode.word, + position: { + start: input.nextNodeStartPosition.start, + end: + input.nextNodeStartPosition.start + + input.measureTextWidth(input.sentenceStructureNode.word.text), + top: input.nextNodeStartPosition.top, + bottom: input.nextNodeStartPosition.top + lineHeight, + }, + }, + nextNodeStartPosition: { + start: + input.nextNodeStartPosition.start + + input.measureTextWidth(input.sentenceStructureNode.word.text) + + wordSpacing, + top: input.nextNodeStartPosition.top, + }, + nextLineStartPosition: input.nextLineStartPosition, + }; +} + +function createSentenceStructureDiagramRangeNode( + input: Input, +): Result { + let nextNodeStartPosition = { ...input.nextNodeStartPosition }; + let nextLineStartPosition = { + start: nextNodeStartPosition.start, + top: input.nextLineStartPosition.top, + }; + const children: SentenceStructureDiagramRangeNode["children"] = []; + for (const child of input.sentenceStructureNode.children) { + const childWidth = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: input.measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: input.measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: input.measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start; + if ( + nextNodeStartPosition.start !== input.nextNodeStartPosition.start && + input.maxWidth < nextNodeStartPosition.start + childWidth + padding + ) { + nextNodeStartPosition = { ...nextLineStartPosition }; + nextLineStartPosition.top += lineHeight + lineSpacing; + } + const result = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }) + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }) + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }); + children.push(result.sentenceStructureDiagramNode); + nextNodeStartPosition = { ...result.nextNodeStartPosition }; + nextLineStartPosition = { ...result.nextLineStartPosition }; + } + + return { + sentenceStructureDiagramNode: { + range: input.sentenceStructureNode.range, + position: { + end: nextNodeStartPosition.start - wordSpacing, + top: input.nextNodeStartPosition.top, + bottom: nextLineStartPosition.top - lineSpacing, + }, + children: children, + }, + nextNodeStartPosition, + nextLineStartPosition: { + start: input.nextLineStartPosition.start, + top: nextLineStartPosition.top, + }, + }; +} + +function createSentenceStructureDiagramCoordinationChildNode( + input: Input, +): Result { + let nextNodeStartPosition = { ...input.nextNodeStartPosition }; + let nextLineStartPosition = { + start: nextNodeStartPosition.start, + top: input.nextLineStartPosition.top, + }; + const children: SentenceStructureDiagramCoordinationChildNode["children"] = + []; + for (const child of input.sentenceStructureNode.children) { + const childWidth = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: input.measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: input.measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: input.measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start; + if ( + nextNodeStartPosition.start !== input.nextNodeStartPosition.start && + input.maxWidth < nextNodeStartPosition.start + childWidth + padding + ) { + nextNodeStartPosition = { ...nextLineStartPosition }; + nextLineStartPosition.top += lineHeight + lineSpacing; + } + const result = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }) + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }) + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }); + children.push(result.sentenceStructureDiagramNode); + nextNodeStartPosition = { ...result.nextNodeStartPosition }; + nextLineStartPosition = { ...result.nextLineStartPosition }; + } + + return { + sentenceStructureDiagramNode: { + coordinationChild: input.sentenceStructureNode.coordinationChild, + position: { + end: nextNodeStartPosition.start - wordSpacing, + top: input.nextNodeStartPosition.top, + bottom: nextLineStartPosition.top - lineSpacing, + }, + children: children, + }, + nextNodeStartPosition, + nextLineStartPosition: { + start: input.nextLineStartPosition.start, + top: nextLineStartPosition.top, + }, + }; +} + +function createSentenceStructureDiagramCoordinationNode( + input: Input, +): Result { + let nextNodeStartPosition = { ...input.nextNodeStartPosition }; + let nextLineStartPosition = { + start: nextNodeStartPosition.start, + top: nextNodeStartPosition.top + lineHeight + lineSpacing, + }; + const children: SentenceStructureDiagramCoordinationNode["children"] = []; + for (const child of input.sentenceStructureNode.children) { + const result = createSentenceStructureDiagramCoordinationChildNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: input.maxWidth, + measureTextWidth: input.measureTextWidth, + }); + children.push(result.sentenceStructureDiagramNode); + nextNodeStartPosition = { ...result.nextLineStartPosition }; + nextLineStartPosition.top += lineHeight + lineSpacing; + } + + return { + sentenceStructureDiagramNode: { + coordination: input.sentenceStructureNode.coordination, + position: { + end: Math.max(...children.map((child) => child.position.end)), + top: input.nextNodeStartPosition.top, + bottom: nextLineStartPosition.top - lineSpacing, + }, + children, + }, + nextNodeStartPosition: { + start: + Math.max(...children.map((child) => child.position.end)) + wordSpacing, + top: input.nextNodeStartPosition.top, + }, + nextLineStartPosition: { + start: input.nextLineStartPosition.start, + top: nextLineStartPosition.top, + }, + }; +} + +export function createStructuredSentenceStructureDiagramTree( + sentenceStructureTree: SentenceStructureTree, + maxWidth: number, + measureTextWidth: (text: string) => number, +): SentenceStructureDiagramTree { + let nextNodeStartPosition = { start: padding, top: padding }; + let nextLineStartPosition = { + start: padding, + top: padding + lineHeight + lineSpacing, + }; + const children: SentenceStructureDiagramTree["children"] = []; + for (const child of sentenceStructureTree.children) { + const childWidth = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: Infinity, + measureTextWidth: measureTextWidth, + }).sentenceStructureDiagramNode.position.end - + nextNodeStartPosition.start; + if ( + padding !== nextNodeStartPosition.start && + maxWidth < nextNodeStartPosition.start + childWidth + padding + ) { + nextNodeStartPosition = { ...nextLineStartPosition }; + nextLineStartPosition.top += lineHeight + lineSpacing; + } + const result = + child.type === "word" + ? createSentenceStructureDiagramWordNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: maxWidth, + measureTextWidth: measureTextWidth, + }) + : child.type === "range" + ? createSentenceStructureDiagramRangeNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: maxWidth, + measureTextWidth: measureTextWidth, + }) + : createSentenceStructureDiagramCoordinationNode({ + sentenceStructureNode: child, + nextNodeStartPosition, + nextLineStartPosition, + maxWidth: maxWidth, + measureTextWidth: measureTextWidth, + }); + children.push(result.sentenceStructureDiagramNode); + nextNodeStartPosition = { ...result.nextNodeStartPosition }; + nextLineStartPosition = { ...result.nextLineStartPosition }; + } + + return { + position: { + start: 0, + end: maxWidth, + top: 0, + bottom: nextLineStartPosition.top - lineSpacing + padding, + }, + children: children, + }; +} diff --git a/packages/sentence-structure-diagram-tree/create-tree.ts b/packages/sentence-structure-diagram-tree/create-tree.ts new file mode 100644 index 0000000..85b8711 --- /dev/null +++ b/packages/sentence-structure-diagram-tree/create-tree.ts @@ -0,0 +1,26 @@ +import type { SentenceStructureTree } from "@sentence-structure-diagram-app/sentence-structure-tree"; +import type { LayoutMode } from "@sentence-structure-diagram-app/sentence-structure-diagram-configurations"; +import type { SentenceStructureDiagramTree } from "./types.js"; +import { createStructuredSentenceStructureDiagramTree } from "./create-structured-sentence-structure-diagram-tree.js"; +import { createLinearSentenceStructureDiagramTree } from "./create-linear-sentence-structure-diagram-tree.js"; + +export function createSentenceStructureDiagramTree( + tree: SentenceStructureTree, + maxWidth: number, + measureTextWidth: (text: string) => number, + layoutMode: LayoutMode, +): SentenceStructureDiagramTree { + if (layoutMode === "structured") { + return createStructuredSentenceStructureDiagramTree( + tree, + maxWidth, + measureTextWidth, + ); + } else { + return createLinearSentenceStructureDiagramTree( + tree, + maxWidth, + measureTextWidth, + ); + } +} diff --git a/packages/sentence-structure-diagram-tree/index.ts b/packages/sentence-structure-diagram-tree/index.ts new file mode 100644 index 0000000..04f379c --- /dev/null +++ b/packages/sentence-structure-diagram-tree/index.ts @@ -0,0 +1,9 @@ +export { createSentenceStructureDiagramTree } from "./create-tree.js"; +export type { + SentenceStructureDiagramWordNode, + SentenceStructureDiagramRangeNode, + SentenceStructureDiagramCoordinationChildNode, + SentenceStructureDiagramCoordinationNode, + SentenceStructureDiagramTree, + SentenceStructureDiagramNode, +} from "./types.js"; diff --git a/packages/sentence-structure-diagram-tree/package.json b/packages/sentence-structure-diagram-tree/package.json new file mode 100644 index 0000000..dbe0906 --- /dev/null +++ b/packages/sentence-structure-diagram-tree/package.json @@ -0,0 +1,19 @@ +{ + "name": "@sentence-structure-diagram-app/sentence-structure-diagram-tree", + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "clean": "rm -r dist" + }, + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-diagram-configurations": "^0.1.0", + "@sentence-structure-diagram-app/sentence-structure-tree": "^0.1.0" + }, + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/packages/sentence-structure-diagram-tree/tsconfig.json b/packages/sentence-structure-diagram-tree/tsconfig.json new file mode 100644 index 0000000..d6a2b39 --- /dev/null +++ b/packages/sentence-structure-diagram-tree/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/packages/sentence-structure-diagram-tree/types.ts b/packages/sentence-structure-diagram-tree/types.ts new file mode 100644 index 0000000..292b911 --- /dev/null +++ b/packages/sentence-structure-diagram-tree/types.ts @@ -0,0 +1,75 @@ +import type { + Coordination, + CoordinationChild, + Range, + Word, +} from "@sentence-structure-diagram-app/sentence-structure-data"; + +export type SentenceStructureDiagramWordNode = { + word: Word; + position: { + start: number; + end: number; + top: number; + bottom: number; + }; +}; + +export type SentenceStructureDiagramRangeNode = { + range: Range; + position: { + end: number; + top: number; + bottom: number; + }; + children: ( + | SentenceStructureDiagramWordNode + | SentenceStructureDiagramRangeNode + | SentenceStructureDiagramCoordinationNode + )[]; +}; + +export type SentenceStructureDiagramCoordinationChildNode = { + coordinationChild: CoordinationChild; + position: { + end: number; + top: number; + bottom: number; + }; + children: ( + | SentenceStructureDiagramWordNode + | SentenceStructureDiagramRangeNode + | SentenceStructureDiagramCoordinationNode + )[]; +}; + +export type SentenceStructureDiagramCoordinationNode = { + coordination: Coordination; + position: { + end: number; + top: number; + bottom: number; + }; + children: SentenceStructureDiagramCoordinationChildNode[]; +}; + +export type SentenceStructureDiagramTree = { + position: { + start: number; + end: number; + top: number; + bottom: number; + }; + children: ( + | SentenceStructureDiagramWordNode + | SentenceStructureDiagramRangeNode + | SentenceStructureDiagramCoordinationNode + )[]; +}; + +export type SentenceStructureDiagramNode = + | SentenceStructureDiagramWordNode + | SentenceStructureDiagramRangeNode + | SentenceStructureDiagramCoordinationChildNode + | SentenceStructureDiagramCoordinationNode + | SentenceStructureDiagramTree; diff --git a/packages/sentence-structure-tree/.gitignore b/packages/sentence-structure-tree/.gitignore new file mode 100644 index 0000000..9b1c8b1 --- /dev/null +++ b/packages/sentence-structure-tree/.gitignore @@ -0,0 +1 @@ +/dist diff --git a/packages/sentence-structure-tree/create-tree.ts b/packages/sentence-structure-tree/create-tree.ts new file mode 100644 index 0000000..548a7e3 --- /dev/null +++ b/packages/sentence-structure-tree/create-tree.ts @@ -0,0 +1,299 @@ +import { + findCoordinationByStartAndEndWordIndex, + findRangeByStartAndEndWordIndex, + type Coordination, + type SentenceStructureData, + type Word, +} from "@sentence-structure-diagram-app/sentence-structure-data"; +import type { + SentenceStructureCoordinationNode, + SentenceStructureRangeNode, + SentenceStructureTree, + SentenceStructureWordNode, +} from "./types.js"; + +function createSentenceStructureWordNode( + word: Word, +): SentenceStructureWordNode { + return { + type: "word", + word, + }; +} + +function createSpanChildren( + sentenceStructureData: SentenceStructureData, + span: { + startWordIndex: number; + endWordIndex: number; + }, +): ( + | SentenceStructureWordNode + | SentenceStructureRangeNode + | SentenceStructureCoordinationNode +)[] { + const children: ( + | SentenceStructureWordNode + | SentenceStructureRangeNode + | SentenceStructureCoordinationNode + )[] = []; + + let currentWordIndex = span.startWordIndex; + while (currentWordIndex <= span.endWordIndex) { + const nestedRange = + sentenceStructureData.ranges + .filter( + (range) => + range.startWordIndex !== span.startWordIndex || + range.endWordIndex !== span.endWordIndex, + ) + .filter( + (range) => + range.startWordIndex === currentWordIndex && + range.endWordIndex <= span.endWordIndex, + ) + .sort((a, b) => b.endWordIndex - a.endWordIndex) + .at(0) ?? null; + const nestedCoordination = + sentenceStructureData.coordinations + .filter( + (coordination) => + coordination.children.at(0)!.startWordIndex === currentWordIndex && + coordination.children.at(-1)!.endWordIndex <= span.endWordIndex, + ) + .sort( + (a, b) => + b.children.at(-1)!.endWordIndex - a.children.at(-1)!.endWordIndex, + ) + .at(0) ?? null; + if (!nestedRange && !nestedCoordination) { + children.push( + createSentenceStructureWordNode( + sentenceStructureData.words[currentWordIndex]!, + ), + ); + currentWordIndex++; + } else if (nestedRange && !nestedCoordination) { + children.push({ + type: "range", + range: nestedRange, + children: createSpanChildren(sentenceStructureData, nestedRange), + }); + currentWordIndex = nestedRange.endWordIndex + 1; + } else if (!nestedRange && nestedCoordination) { + children.push( + createSentenceStructureCoordinationNode( + sentenceStructureData, + nestedCoordination, + ), + ); + currentWordIndex = nestedCoordination.children.at(-1)!.endWordIndex + 1; + } else if (nestedRange && nestedCoordination) { + const nestedRangeEndWordIndex = nestedRange.endWordIndex; + const nestedCoordinationEndWordIndex = + nestedCoordination.children.at(-1)!.endWordIndex; + if (nestedCoordinationEndWordIndex < nestedRangeEndWordIndex) { + children.push({ + type: "range", + range: nestedRange, + children: createSpanChildren(sentenceStructureData, nestedRange), + }); + currentWordIndex = nestedRangeEndWordIndex + 1; + } else { + children.push( + createSentenceStructureCoordinationNode( + sentenceStructureData, + nestedCoordination, + ), + ); + currentWordIndex = nestedCoordinationEndWordIndex + 1; + } + } + } + + return children; +} + +function createSentenceStructureCoordinationNode( + sentenceStructureData: SentenceStructureData, + coordination: Coordination, +): SentenceStructureCoordinationNode { + const children: SentenceStructureCoordinationNode["children"] = + coordination.children.map((child) => { + const nestedRange = findRangeByStartAndEndWordIndex( + sentenceStructureData, + { + startWordIndex: child.startWordIndex, + endWordIndex: child.endWordIndex, + }, + ); + const nestedCoordination = findCoordinationByStartAndEndWordIndex( + sentenceStructureData, + { + startWordIndex: child.startWordIndex, + endWordIndex: child.endWordIndex, + }, + ); + if (nestedRange && nestedCoordination) { + return { + type: "coordination-child", + coordinationChild: child, + children: [ + { + type: "range", + range: nestedRange, + children: [ + createSentenceStructureCoordinationNode( + sentenceStructureData, + nestedCoordination, + ), + ], + }, + ], + }; + } else if (nestedRange) { + return { + type: "coordination-child", + coordinationChild: child, + children: [ + child.startWordIndex === child.endWordIndex + ? { + type: "range", + range: nestedRange, + children: [ + createSentenceStructureWordNode( + sentenceStructureData.words[child.startWordIndex]!, + ), + ], + } + : { + type: "range", + range: nestedRange, + children: createSpanChildren( + sentenceStructureData, + nestedRange, + ), + }, + ], + }; + } else if (nestedCoordination) { + return { + type: "coordination-child", + coordinationChild: child, + children: [ + createSentenceStructureCoordinationNode( + sentenceStructureData, + nestedCoordination, + ), + ], + }; + } else { + return child.startWordIndex === child.endWordIndex + ? { + type: "coordination-child", + coordinationChild: child, + children: [ + createSentenceStructureWordNode( + sentenceStructureData.words[child.startWordIndex]!, + ), + ], + } + : { + type: "coordination-child", + coordinationChild: child, + children: createSpanChildren(sentenceStructureData, child), + }; + } + }); + + return { + type: "coordination", + coordination, + children, + }; +} + +export function createTree( + sentenceStructureData: SentenceStructureData, +): SentenceStructureTree { + const nestedRange = findRangeByStartAndEndWordIndex(sentenceStructureData, { + startWordIndex: 0, + endWordIndex: sentenceStructureData.words.length - 1, + }); + const nestedCoordination = findCoordinationByStartAndEndWordIndex( + sentenceStructureData, + { + startWordIndex: 0, + endWordIndex: sentenceStructureData.words.length - 1, + }, + ); + if (sentenceStructureData.words.length === 0) { + return { + type: "tree", + children: [], + }; + } + if (nestedRange && nestedCoordination) { + return { + type: "tree", + children: [ + { + type: "range", + range: nestedRange, + children: [ + createSentenceStructureCoordinationNode( + sentenceStructureData, + nestedCoordination, + ), + ], + }, + ], + }; + } else if (nestedRange) { + return { + type: "tree", + children: [ + sentenceStructureData.words.length === 1 + ? { + type: "range", + range: nestedRange, + children: [ + createSentenceStructureWordNode( + sentenceStructureData.words[0]!, + ), + ], + } + : { + type: "range", + range: nestedRange, + children: createSpanChildren(sentenceStructureData, nestedRange), + }, + ], + }; + } else if (nestedCoordination) { + return { + type: "tree", + children: [ + createSentenceStructureCoordinationNode( + sentenceStructureData, + nestedCoordination, + ), + ], + }; + } else { + return sentenceStructureData.words.length === 1 + ? { + type: "tree", + children: [ + createSentenceStructureWordNode(sentenceStructureData.words[0]!), + ], + } + : { + type: "tree", + children: createSpanChildren(sentenceStructureData, { + startWordIndex: 0, + endWordIndex: sentenceStructureData.words.length - 1, + }), + }; + } +} diff --git a/packages/sentence-structure-tree/index.ts b/packages/sentence-structure-tree/index.ts new file mode 100644 index 0000000..ada3a88 --- /dev/null +++ b/packages/sentence-structure-tree/index.ts @@ -0,0 +1,9 @@ +export { createTree } from "./create-tree.js"; +export type { + SentenceStructureWordNode, + SentenceStructureRangeNode, + SentenceStructureCoordinationChildNode, + SentenceStructureCoordinationNode, + SentenceStructureTree, + SentenceStructureNode, +} from "./types.js"; diff --git a/packages/sentence-structure-tree/package.json b/packages/sentence-structure-tree/package.json new file mode 100644 index 0000000..ab018cf --- /dev/null +++ b/packages/sentence-structure-tree/package.json @@ -0,0 +1,17 @@ +{ + "name": "@sentence-structure-diagram-app/sentence-structure-tree", + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "scripts": { + "build": "tsc", + "build:watch": "tsc --watch", + "clean": "rm -r dist" + }, + "dependencies": { + "@sentence-structure-diagram-app/sentence-structure-data": "^0.1.0" + }, + "devDependencies": { + "typescript": "^5.9.3" + } +} diff --git a/packages/sentence-structure-tree/tsconfig.json b/packages/sentence-structure-tree/tsconfig.json new file mode 100644 index 0000000..d6a2b39 --- /dev/null +++ b/packages/sentence-structure-tree/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/packages/sentence-structure-tree/types.ts b/packages/sentence-structure-tree/types.ts new file mode 100644 index 0000000..ff3f8f4 --- /dev/null +++ b/packages/sentence-structure-tree/types.ts @@ -0,0 +1,53 @@ +import { + type Coordination, + type CoordinationChild, + type Range, + type Word, +} from "@sentence-structure-diagram-app/sentence-structure-data"; + +export type SentenceStructureWordNode = { + type: "word"; + word: Word; +}; + +export type SentenceStructureRangeNode = { + type: "range"; + range: Range; + children: ( + | SentenceStructureWordNode + | SentenceStructureRangeNode + | SentenceStructureCoordinationNode + )[]; +}; + +export type SentenceStructureCoordinationChildNode = { + type: "coordination-child"; + coordinationChild: CoordinationChild; + children: ( + | SentenceStructureWordNode + | SentenceStructureRangeNode + | SentenceStructureCoordinationNode + )[]; +}; + +export type SentenceStructureCoordinationNode = { + type: "coordination"; + coordination: Coordination; + children: SentenceStructureCoordinationChildNode[]; +}; + +export type SentenceStructureTree = { + type: "tree"; + children: ( + | SentenceStructureWordNode + | SentenceStructureRangeNode + | SentenceStructureCoordinationNode + )[]; +}; + +export type SentenceStructureNode = + | SentenceStructureWordNode + | SentenceStructureRangeNode + | SentenceStructureCoordinationChildNode + | SentenceStructureCoordinationNode + | SentenceStructureTree; diff --git a/render.yaml b/render.yaml new file mode 100644 index 0000000..b636cca --- /dev/null +++ b/render.yaml @@ -0,0 +1,13 @@ +services: + - type: web + runtime: node + name: sentence-structure-diagram-app-backend + region: singapore + plan: free + buildCommand: npm ci && npm run build + startCommand: cd packages/backend && npm start + envVars: + - key: WEB_ORIGIN + value: https://chvmvd.github.io + - key: GEMINI_API_KEY + sync: false diff --git a/src/App.tsx b/src/App.tsx deleted file mode 100644 index eeee7f0..0000000 --- a/src/App.tsx +++ /dev/null @@ -1,859 +0,0 @@ -import { - type CSSProperties, - useEffect, - useLayoutEffect, - useMemo, - useRef, - useState, -} from "react"; -import { - AppBar, - Toolbar, - Button, - Box, - Paper, - TextField, - IconButton, - Chip, -} from "@mui/material"; -import UploadFileIcon from "@mui/icons-material/UploadFile"; -import DownloadIcon from "@mui/icons-material/IosShare"; -import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"; -import EditIcon from "@mui/icons-material/ModeEditOutline"; -import DrawIcon from "@mui/icons-material/Draw"; -import LinkIcon from "@mui/icons-material/CallMerge"; -import CloseIcon from "@mui/icons-material/Close"; - -// ================================================== -// Types (explicit, minimal) -// ================================================== - -type Label = "S" | "V" | "O" | "C" | "M"; -type RangeKind = "phrase" | "clause" | "modifier" | "underline"; - -type Range = { id: string; type: RangeKind; start: number; end: number }; -type LabelAnnotation = { id: string; targetId: string; label: Label }; -type Relation = { id: string; fromId: string; toId: string }; - -type DocumentState = { - text: string; - ranges: Range[]; - labels: LabelAnnotation[]; - rels: Relation[]; -}; - -// ================================================== -// Helpers (modern browsers only) -// ================================================== - -const createId = () => crypto.randomUUID(); - -const tokenize = (input: string) => - input.trim() - ? input - .replace(/\s+/g, " ") - .trim() - .match( - /[\u2018\u2019\u201C\u201D"']|[(){}\[\]]|—|–|\/|[.,;:!?]|[A-Za-z]+(?:'[A-Za-z]+)?|\d+|\S/gi - ) ?? [] - : []; -const isPunctuationToken = (token: string) => - /^[.,;:!?(){}\[\]"'—–]$/.test(token) || /^[、。]$/.test(token); - -// Geometry (for underlines/labels/arrows) -type TokenRect = { left: number; right: number; top: number; bottom: number }; -const computeSpanGeometry = ( - tokenRects: (TokenRect | undefined)[], - startIndex: number, - endIndex: number -) => { - const rects = tokenRects - .slice(startIndex, endIndex + 1) - .filter(Boolean) as TokenRect[]; - if (!rects.length) return null; - const leftX = Math.min(...rects.map((r) => r.left)); - const rightX = Math.max(...rects.map((r) => r.right)); - const topY = Math.min(...rects.map((r) => r.top)); - const bottomY = Math.max(...rects.map((r) => r.bottom)); - const EPS = 6; - const segments: { key: number; y: number; x1: number; x2: number }[] = []; - rects.forEach((r) => { - const same = segments.find((L) => Math.abs(L.key - r.top) <= EPS); - if (same) { - same.y = Math.max(same.y, r.bottom); - same.x1 = Math.min(same.x1, r.left); - same.x2 = Math.max(same.x2, r.right); - } else { - segments.push({ key: r.top, y: r.bottom, x1: r.left, x2: r.right }); - } - }); - segments.sort((a, b) => a.key - b.key); - return { - midX: (leftX + rightX) / 2, - topY, - botY: bottomY, - segs: segments.map((L) => ({ y: L.y, x1: L.x1, x2: L.x2 })), - } as const; -}; -const buildArrowPath = (x1: number, y1: number, x2: number, y2: number) => { - const span = Math.max(1, Math.abs(x2 - x1)); - const lift = 18 + Math.min(48, span * 0.35); - const apexY = Math.min(y1, y2) - lift; - return { - d: `M ${x1},${y1} C ${x1},${apexY} ${x2},${apexY} ${x2},${y2}`, - midX: (x1 + x2) / 2, - midY: apexY, - }; -}; - -// ================================================== -// Component: header + canvas (first public release) -// ================================================== - -export default function App() { - // View mode - const [viewMode, setViewMode] = useState<"edit" | "annotate">("annotate"); - - // Document state - const [documentState, setDocumentState] = useState({ - text: "When he arrived, the teacher quickly explained the rules to the students.", - ranges: [], - labels: [], - rels: [], - }); - - // Selection / active range / pending relation - const [activeRangeId, setActiveRangeId] = useState(null); - const [pendingRelationFromId, setPendingRelationFromId] = useState< - string | null - >(null); - const [dragAnchorIndex, setDragAnchorIndex] = useState(null); - const [dragFocusIndex, setDragFocusIndex] = useState(null); - const selection = useMemo( - () => - dragAnchorIndex == null || dragFocusIndex == null - ? null - : { - start: Math.min(dragAnchorIndex, dragFocusIndex), - end: Math.max(dragAnchorIndex, dragFocusIndex), - }, - [dragAnchorIndex, dragFocusIndex] - ); - - // Tokens & rects - const tokenList = useMemo( - () => tokenize(documentState.text), - [documentState.text] - ); - const canvasRef = useRef(null); - const tokenRefs = useRef<(HTMLSpanElement | null)[]>([]); - const [tokenRects, setTokenRects] = useState<(TokenRect | undefined)[]>([]); - - const measureTokenRects = () => { - const root = canvasRef.current; - if (!root) return; - const rootBox = root.getBoundingClientRect(); - setTokenRects( - tokenList.map((_, i) => { - const el = tokenRefs.current[i]; - if (!el) return undefined; - const b = el.getBoundingClientRect(); - return { - left: b.left - rootBox.left, - right: b.right - rootBox.left, - top: b.top - rootBox.top, - bottom: b.bottom - rootBox.top, - } as TokenRect; - }) - ); - }; - - useLayoutEffect(() => { - if (viewMode === "annotate") measureTokenRects(); - }, [ - viewMode, - tokenList.length, - documentState.ranges.length, - documentState.labels.length, - documentState.rels.length, - ]); - useEffect(() => { - const on = () => measureTokenRects(); - window.addEventListener("resize", on); - return () => window.removeEventListener("resize", on); - }, []); - useEffect(() => { - if (!canvasRef.current) return; - const ro = new ResizeObserver(() => measureTokenRects()); - ro.observe(canvasRef.current); - return () => ro.disconnect(); - }, []); - - // Helpers - const snapToNearestNonPunctuation = (index: number) => { - if (!isPunctuationToken(tokenList[index] ?? "")) return index; - for (let j = index - 1; j >= 0 && index - j <= 6; j--) - if (!isPunctuationToken(tokenList[j])) return j; - for (let j = index + 1; j < tokenList.length && j - index <= 6; j++) - if (!isPunctuationToken(tokenList[j])) return j; - return index; - }; - const findTopmostRangeAtToken = (index: number) => { - const hit = documentState.ranges.filter( - (r) => index >= r.start && index <= r.end - ); - return hit.length ? hit[hit.length - 1] : null; - }; - const computeToolbarAnchor = ( - start: number, - end: number, - placeAbove: boolean - ) => { - const rects = tokenRects - .slice(start, end + 1) - .filter(Boolean) as TokenRect[]; - if (!rects.length) return null; - const left = Math.min(...rects.map((r) => r.left)); - const right = Math.max(...rects.map((r) => r.right)); - const top = Math.min(...rects.map((r) => r.top)); - const bottom = Math.max(...rects.map((r) => r.bottom)); - return { - x: (left + right) / 2, - y: placeAbove ? Math.max(0, top - 36) : bottom + 10, - }; - }; - - // Bracket markers for non-underline ranges - const openingBrackets = useMemo(() => { - const map: Record = {}; - for (let i = 0; i < tokenList.length; i++) map[i] = []; - documentState.ranges.forEach((range) => { - if (range.type !== "underline") - map[range.start].push( - range.type === "phrase" ? "<" : range.type === "clause" ? "{" : "(" - ); - }); - return map; - }, [documentState.ranges, tokenList.length]); - const closingBrackets = useMemo(() => { - const map: Record = {}; - for (let i = 0; i < tokenList.length; i++) map[i] = []; - documentState.ranges.forEach((range) => { - if (range.type !== "underline") - map[range.end].push( - range.type === "phrase" ? ">" : range.type === "clause" ? "}" : ")" - ); - }); - return map; - }, [documentState.ranges, tokenList.length]); - - // Mutations - const createRange = (type: RangeKind) => { - if (!selection) return; - const id = createId(); - setDocumentState((v) => ({ - ...v, - ranges: [ - ...v.ranges, - { id, type, start: selection.start, end: selection.end }, - ], - })); - setActiveRangeId(id); - setDragAnchorIndex(null); - setDragFocusIndex(null); - }; - const addLabelToActiveRange = (label: Label) => { - if (!activeRangeId) return; - setDocumentState((v) => ({ - ...v, - labels: [...v.labels, { id: createId(), targetId: activeRangeId, label }], - })); - }; - const clearAllAnnotations = () => { - setDocumentState((v) => ({ ...v, ranges: [], labels: [], rels: [] })); - setActiveRangeId(null); - setPendingRelationFromId(null); - setDragAnchorIndex(null); - setDragFocusIndex(null); - }; - const startRelation = () => { - if (activeRangeId) setPendingRelationFromId(activeRangeId); - }; - const cancelRelation = () => setPendingRelationFromId(null); - const commitRelation = (toId: string) => { - if (!pendingRelationFromId || pendingRelationFromId === toId) - return cancelRelation(); - setDocumentState((v) => ({ - ...v, - rels: [ - ...v.rels, - { id: createId(), fromId: pendingRelationFromId, toId }, - ], - })); - cancelRelation(); - }; - const deleteActiveRange = () => { - if (!activeRangeId) return; - setDocumentState((v) => ({ - ...v, - labels: v.labels.filter((l) => l.targetId !== activeRangeId), - rels: v.rels.filter( - (r) => r.fromId !== activeRangeId && r.toId !== activeRangeId - ), - ranges: v.ranges.filter((r) => r.id !== activeRangeId), - })); - setActiveRangeId(null); - }; - - // I/O (pure JSON; ignore legacy fields if present) - const exportJSON = () => { - const blob = new Blob([JSON.stringify(documentState, null, 2)], { - type: "application/json", - }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = "annotation.json"; - a.click(); - URL.revokeObjectURL(url); - }; - const importJSON = (file: File) => { - const reader = new FileReader(); - reader.onload = () => { - try { - const raw = JSON.parse( - String(reader.result) - ) as Partial & { version?: unknown }; - const next: DocumentState = { - text: raw.text ?? "", - ranges: Array.isArray(raw.ranges) ? (raw.ranges) : [], - labels: Array.isArray(raw.labels) - ? (raw.labels) - : [], - rels: Array.isArray(raw.rels) ? (raw.rels) : [], - }; - setDocumentState(next); - setActiveRangeId(null); - setPendingRelationFromId(null); - setDragAnchorIndex(null); - setDragFocusIndex(null); - requestAnimationFrame(measureTokenRects); - } catch { - alert("インポートに失敗しました"); - } - }; - reader.readAsText(file); - }; - - // Derivations - const selectionAnchor = selection - ? computeToolbarAnchor(selection.start, selection.end, false) - : null; - const activeAnchor = activeRangeId - ? (() => { - const r = documentState.ranges.find((x) => x.id === activeRangeId); - return r ? computeToolbarAnchor(r.start, r.end, true) : null; - })() - : null; - const canvasHeight = canvasRef.current?.getBoundingClientRect().height || 0; - - const relationShapes = useMemo( - () => - documentState.rels - .map((rel, index) => { - const from = documentState.ranges.find((x) => x.id === rel.fromId); - const to = documentState.ranges.find((x) => x.id === rel.toId); - if (!from || !to) return null; - const fg = computeSpanGeometry(tokenRects, from.start, from.end); - const tg = computeSpanGeometry(tokenRects, to.start, to.end); - if (!fg || !tg) return null; - const lift = 6 * (index % 3); - const { d, midX, midY } = buildArrowPath( - fg.midX, - fg.topY - 2 - lift, - tg.midX, - tg.topY - 2 - lift - ); - return { id: rel.id, d, midX, midY }; - }) - .filter(Boolean) as { - id: string; - d: string; - midX: number; - midY: number; - }[], - [documentState.rels, documentState.ranges, tokenRects] - ); - - return ( - - - - Annotation - - - - - - - - - - - - - - - {viewMode === "edit" ? ( - - setDocumentState((v) => ({ ...v, text: e.target.value })) - } - placeholder="ここに英文を編集" - /> - ) : ( - - {/* Arrows (non-interactive SVG) */} - - - - - - - {relationShapes.map((shape) => ( - - ))} - - - {/* Arrow delete buttons (HTML) */} - - {relationShapes.map((shape) => ( - - setDocumentState((v) => ({ - ...v, - rels: v.rels.filter((x) => x.id !== shape.id), - })) - } - > - × - - ))} - - - {/* Tokens with bracket markers */} - - {tokenList.map((tokenText, tokenIndex) => { - const inSelection = !!( - selection && - tokenIndex >= selection.start && - tokenIndex <= selection.end && - !isPunctuationToken(tokenText) - ); - const inActiveRange = !!( - activeRangeId && - documentState.ranges.find( - (r) => - r.id === activeRangeId && - tokenIndex >= r.start && - tokenIndex <= r.end - ) - ); - const tokenStyle: CSSProperties = { - position: "relative", - display: "inline-block", - padding: "0 8px", - borderRadius: 8, - marginBottom: 12, - userSelect: "none", - cursor: !isPunctuationToken(tokenText) - ? "pointer" - : "default", - }; - if (inSelection) { - tokenStyle.outline = "2px solid rgba(99,102,241,.6)"; - (tokenStyle as any).background = "rgba(238,242,255,1)"; - } else if (inActiveRange) { - tokenStyle.outline = "2px solid rgba(34,197,94,.6)"; - } - return ( - - {openingBrackets[tokenIndex]?.length ? ( - - {openingBrackets[tokenIndex].join("")} - - ) : null} - - (tokenRefs.current[tokenIndex] = el)} - style={tokenStyle} - onMouseDown={() => { - const j = snapToNearestNonPunctuation(tokenIndex); - setDragAnchorIndex(j); - setDragFocusIndex(j); - }} - onMouseEnter={(e) => { - if (dragAnchorIndex !== null && (e.buttons & 1) === 1) - setDragFocusIndex( - snapToNearestNonPunctuation(tokenIndex) - ); - }} - onMouseUp={() => { - if (dragAnchorIndex !== null) - setDragFocusIndex( - snapToNearestNonPunctuation(tokenIndex) - ); - }} - onClick={() => { - const r = findTopmostRangeAtToken(tokenIndex); - if (!r) { - setActiveRangeId(null); - setPendingRelationFromId(null); - return; - } - if (pendingRelationFromId) commitRelation(r.id); - else setActiveRangeId(r.id); - }} - > - {tokenText} - - - {closingBrackets[tokenIndex]?.length ? ( - - {closingBrackets[tokenIndex].join("")} - - ) : null} - - ); - })} - - - {/* Selection toolbar (pill) */} - {selection && selectionAnchor && ( - - - createRange("phrase")} - /> - createRange("clause")} - /> - createRange("modifier")} - /> - createRange("underline")} - /> - - - )} - - {/* Active toolbar (pill) */} - {activeRangeId && activeAnchor && !selection && ( - - - {(["S", "V", "O", "C", "M"] as Label[]).map((L) => ( - addLabelToActiveRange(L)} - /> - ))} - {!pendingRelationFromId && ( - } - label="矢印" - onClick={startRelation} - /> - )} - {pendingRelationFromId && ( - } - label="キャンセル" - onClick={cancelRelation} - /> - )} - - - - )} - - {/* Underlines + Labels */} - - {documentState.ranges - .filter((r) => r.type === "underline") - .flatMap((range) => { - const g = computeSpanGeometry( - tokenRects, - range.start, - range.end - ); - if (!g) return []; - return g.segs.map((seg, idx) => ( - - )); - })} - - - - {documentState.labels.map((labelAnno) => { - const range = documentState.ranges.find( - (r) => r.id === labelAnno.targetId - ); - if (!range) return null; - const g = computeSpanGeometry( - tokenRects, - range.start, - range.end - ); - if (!g) return null; - return ( - - {labelAnno.label} - - ); - })} - - - )} - - - - - Mode: {viewMode} - - - Tokens: {tokenList.length} - - - Ranges: {documentState.ranges.length} - - - Labels: {documentState.labels.length} - - - Rels: {documentState.rels.length} - - - - - ); -} diff --git a/src/main.tsx b/src/main.tsx deleted file mode 100644 index 4aff025..0000000 --- a/src/main.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import App from './App.tsx' - -createRoot(document.getElementById('root')!).render( - - - , -)