diff --git a/.codegraph/.gitignore b/.codegraph/.gitignore new file mode 100644 index 0000000..d20c0fe --- /dev/null +++ b/.codegraph/.gitignore @@ -0,0 +1,5 @@ +# CodeGraph data files — local to each machine, not for committing. +# Ignore everything in .codegraph/ except this file itself, so transient +# files (the database, daemon.pid, sockets, logs) never show up in git. +* +!.gitignore diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..02f2612 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,24 @@ +# EditorConfig — 跨编辑器统一代码风格 +# https://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = crlf +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.{rs,toml}] +indent_size = 4 + +[*.{yml,yaml}] +indent_size = 2 + +[Makefile] +indent_style = tab diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..43b96ad --- /dev/null +++ b/.gitattributes @@ -0,0 +1,32 @@ +# Git 行尾符规范化 +# 本仓库统一 CRLF(Windows 原生项目) + +# 源码文本文件 +*.ts text eol=crlf +*.tsx text eol=crlf +*.js text eol=crlf +*.json text eol=crlf +*.html text eol=crlf +*.css text eol=crlf +*.md text eol=crlf +*.rs text eol=crlf +*.toml text eol=crlf +*.yml text eol=crlf +*.yaml text eol=crlf +*.svg text eol=crlf +*.txt text eol=crlf +*.editorconfig text eol=crlf +*.gitattributes text eol=crlf +*.gitignore text eol=crlf +LICENSE text eol=crlf + +# 二进制文件 +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.pdf binary +*.dll binary +*.exe binary +*.nsis binary diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..0497638 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,20 @@ +# 代码所有者 — 自动分配 PR 审查 +# https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +# 全局所有者 +* @LHY0125 + +# Rust 代码 +/core/ @LHY0125 +/cli/ @LHY0125 +/gui/ @LHY0125 +/Cargo.toml @LHY0125 +/rust-toolchain.toml @LHY0125 + +# 前端代码 +/src/ @LHY0125 +/tests/ @LHY0125 +/e2e/ @LHY0125 + +# CI/CD 和配置文件 +/.github/ @LHY0125 diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..67edefb --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# 开源赞助 +# 支持 PathEditor 的开发 + +github: LHY0125 +# 如需定制功能或商业授权,请通过 GitHub Issues 联系 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..bec6d24 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,73 @@ +# Dependabot 自动依赖更新配置 +# https://docs.github.com/code-security/dependabot/dependabot-version-updates + +version: 2 +updates: + # npm 前端依赖 + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "Asia/Shanghai" + versioning-strategy: "auto" + allow: + - dependency-type: "all" + labels: + - "dependencies" + - "javascript" + commit-message: + prefix: "chore(deps)" + prefix-development: "chore(deps-dev)" + open-pull-requests-limit: 5 + groups: + react: + patterns: + - "react" + - "react-dom" + - "@types/react" + - "@types/react-dom" + tauri: + patterns: + - "@tauri-apps/*" + testing: + patterns: + - "@testing-library/*" + - "@playwright/test" + - "vitest" + - "jsdom" + eslint: + patterns: + - "eslint" + - "eslint-plugin-*" + - "typescript-eslint" + - "globals" + - "@eslint/js" + + # Cargo Rust 依赖 + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "Asia/Shanghai" + labels: + - "dependencies" + - "rust" + commit-message: + prefix: "chore(deps)" + prefix-development: "chore(deps-dev)" + open-pull-requests-limit: 3 + + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + labels: + - "dependencies" + - "ci" + commit-message: + prefix: "ci(deps)" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 302a499..8cf9cef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ permissions: jobs: frontend: - name: 前端检查 (TypeScript + Lint + Test) + name: 前端检查 (格式 + 类型 + Lint + 测试 + 覆盖率) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -24,21 +24,35 @@ jobs: - run: npm ci + - name: Prettier 格式检查 + run: npx prettier --check "src/**/*.{ts,tsx}" "tests/**/*.{ts,tsx}" "e2e/**/*.ts" + - name: TypeScript 类型检查 run: npx tsc -b --noEmit - name: ESLint run: npx eslint src/ tests/ - - name: Vitest 测试 - run: npm test + - name: Vitest 测试 + 覆盖率 + run: npx vitest run --coverage + + - name: 上传覆盖率到 Codecov + uses: codecov/codecov-action@v5 + with: + files: ./coverage/cobertura-coverage.xml + flags: frontend + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} rust: - name: Rust 检查 (Check + Clippy + Test) + name: Rust 检查 (格式 + Check + Clippy + Test) runs-on: windows-latest steps: - uses: actions/checkout@v4 + - name: Cargo Format + run: cargo fmt --check + - name: Cargo Check run: cargo check diff --git a/.gitignore b/.gitignore index 792a220..5f86d8b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,21 @@ dist dist-ssr *.local +# Coverage +coverage/ +*.lcov + +# Sync conflicts +*.sync-conflict-* + +# Test artifacts +test-results/ +playwright-report/ +.nyc_output/ + # Editor directories and files .vscode/* +.codegraph/* !.vscode/extensions.json .idea .DS_Store @@ -22,8 +35,16 @@ dist-ssr *.njsproj *.sln *.sw? + +# AI assistant .claude/ CLAUDE.md + +# Platform e2e/debug-screenshot.png -test-results/ target/ + +# Archive +*.zip +*.7z +*.tar.gz diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..0a4b97d --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..2588642 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "default": true, + "MD013": false, + "MD033": { + "allowed_elements": ["img", "br", "kbd", "summary", "details"] + }, + "MD041": false +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..3880956 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,10 @@ +node_modules +dist +dist-ssr +target +*.local +*.log +test-results +coverage +Cargo.lock +package-lock.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..6dd41b5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "printWidth": 100, + "tabWidth": 2, + "endOfLine": "crlf", + "arrowParens": "always", + "bracketSpacing": true +} diff --git a/README.md b/README.md index f5a23d9..a606923 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,33 @@ typescript license tests + coverage + platform CI

--- +## 截图 + +> 📸 将截图放置在此区域(`docs/screenshots/` 目录),并取消注释对应的图片链接。 + + + +--- + ## 简介 PathEditor 是 Windows PATH 环境变量的可视化管理工具。支持系统变量和用户变量的增删改查、拖拽排序、一键清理无效路径、导入导出以及完整的撤销/重做。 @@ -251,18 +273,18 @@ npx tauri build ### 技术栈 -| 层 | 技术 | -|---|---| -| 前端框架 | React 19 + TypeScript (strict) | -| UI 样式 | Tailwind CSS 4 | -| 状态管理 | Zustand | -| 国际化 | i18next | -| 桌面框架 | Tauri 2.x | -| 核心库 | Rust workspace (core + gui + cli) | -| 前端测试 | Vitest (72 个测试) | -| Rust 测试 | cargo test (10 个测试) | -| 构建 | Vite + Cargo | -| 打包 | NSIS | +| 层 | 技术 | +| --------- | --------------------------------- | +| 前端框架 | React 19 + TypeScript (strict) | +| UI 样式 | Tailwind CSS 4 | +| 状态管理 | Zustand | +| 国际化 | i18next | +| 桌面框架 | Tauri 2.x | +| 核心库 | Rust workspace (core + gui + cli) | +| 前端测试 | Vitest (72 个测试) | +| Rust 测试 | cargo test (10 个测试) | +| 构建 | Vite + Cargo | +| 打包 | NSIS | ### 项目结构 @@ -290,15 +312,15 @@ tests/unit/ # 前端单元测试 ## 快捷键 -| 快捷键 | 功能 | -|--------|------| +| 快捷键 | 功能 | +| -------- | -------- | | `Ctrl+N` | 新建路径 | -| `Ctrl+S` | 保存 | -| `Ctrl+Z` | 撤销 | -| `Ctrl+Y` | 重做 | -| `Ctrl+F` | 搜索 | +| `Ctrl+S` | 保存 | +| `Ctrl+Z` | 撤销 | +| `Ctrl+Y` | 重做 | +| `Ctrl+F` | 搜索 | | `Delete` | 删除选中 | -| `F1` | 帮助 | +| `F1` | 帮助 | ## 贡献 diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..29b8af0 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,48 @@ +# 路线图 + +PathEditor 的未来发展方向。 + +## v5.1 (下一个版本) + +- [ ] **CLI 模块化** — `cli/src/main.rs` 拆分为 `commands/` 子模块 +- [ ] **自动更新** — 内置 Tauri updater,无需手动下载安装包 +- [ ] **深色模式优化** — 对齐 Windows 系统主题自动切换 +- [ ] **性能优化** — 虚拟滚动支持超长 PATH 列表(1000+ 条目) + +## v5.2 + +- [ ] **PATH 历史快照** — 保存每次修改的时间线,支持回退到任意历史节点 +- [ ] **规则引擎** — 自定义 PATH 整理规则(如「所有 Python 路径放最前」) +- [ ] **收藏夹** — 常用路径快速添加 +- [ ] **冲突解决方案引导** — 可视化的可执行文件冲突对比与解决建议 + +## v6.0 (长期) + +- [ ] **跨平台支持** — 适配 Linux (`/etc/environment` + `~/.profile`) 和 macOS (`path_helper`) +- [ ] **Web 管理面板** — 远程管理多台 Windows 服务器的 PATH 环境变量 +- [ ] **插件系统** — 第三方扩展生态(如 Anaconda/VSCode/VS 自动检测与配置) +- [ ] **Windows Package Manager 集成** — 与 winget/chocolatey 联动,检测包管理器安装的路径 + +## 已交付 + +### v5.0.0 + +- ✅ Cargo workspace 三层架构 (core + gui + cli) +- ✅ CLI 命令行工具 (18 条命令) +- ✅ 冲突检测 + 工具清单 +- ✅ 配置文件管理 +- ✅ 撤销/重做 (10 种操作) +- ✅ 中英双语界面 +- ✅ CI/CD 自动化 + +### v4.x 系列 + +- ✅ Tauri 2.x 重写 +- ✅ 路径验证 (红色/橙色标记) +- ✅ 导入/导出 JSON/CSV/TXT +- ✅ 深色/浅色模式 +- ✅ 全局键盘快捷键 + +--- + +欢迎通过 [Issues](https://github.com/LHY0125/PathEditor/issues) 提交功能建议! diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 0000000..0edf910 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,45 @@ +# 获取帮助 + +## 📖 文档 + +- [README](README.md) — 项目简介、功能列表、安装指南 +- [CONTRIBUTING](CONTRIBUTING.md) — 贡献指南 +- [CHANGELOG](CHANGELOG.md) — 版本变更记录 +- [ROADMAP](ROADMAP.md) — 未来规划 +- [SECURITY](SECURITY.md) — 安全政策 + +## 🐛 报告 Bug + +1. 先搜索 [Issues](https://github.com/LHY0125/PathEditor/issues) 确认未被报告 +2. 使用 **Bug Report** 模板创建新 Issue +3. 提供系统信息(Windows 版本、PathEditor 版本) +4. 附上复现步骤和截图 + +## 💡 功能建议 + +1. 检查 [ROADMAP](ROADMAP.md) 确认不在已有计划中 +2. 使用 **Feature Request** 模板创建新 Issue +3. 描述使用场景和期望行为 + +## ❓ 常见问题 + +### CLI 命令找不到? + +```bash +patheditor --help +``` + +确保已通过 `cargo install --path cli` 安装,且 `~/.cargo/bin` 在 PATH 中。 + +### 提示权限不足? + +编辑系统 PATH 需要管理员权限。右键以管理员身份运行,或使用 CLI `patheditor check-admin` 检测。 + +### 保存后环境变量未生效? + +PathEditor 会自动广播 `WM_SETTINGCHANGE`,但部分程序需要手动重启才能识别新 PATH。 + +## 📧 联系 + +- GitHub Issues: [LHY0125/PathEditor](https://github.com/LHY0125/PathEditor/issues) +- 安全问题: 参见 [SECURITY.md](SECURITY.md) diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..c4c9714 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,12 @@ +/** @type {import('@commitlint/types').UserConfig} */ +export default { + extends: ['@commitlint/config-conventional'], + rules: { + 'type-enum': [ + 2, + 'always', + ['feat', 'fix', 'refactor', 'docs', 'test', 'chore', 'perf', 'ci', 'style', 'revert'], + ], + 'subject-case': [0], + }, +}; diff --git a/docs/REMAINING-ISSUES.md b/docs/REMAINING-ISSUES.md new file mode 100644 index 0000000..9677019 --- /dev/null +++ b/docs/REMAINING-ISSUES.md @@ -0,0 +1,36 @@ +# 未修复问题清单 + +> 从 v5.1 全面代码审查中筛选,暂不修复,留待后续评估。 + +--- + +## 1. CLI main.rs 单体文件 (639 行) + +**严重级别**: LOW +**文件**: `cli/src/main.rs` + +**问题**: 所有 18 条 CLI 命令集中在一个文件中。 + +**建议**: 当前规模尚可维护,等到命令数超过 25 条或文件超过 1000 行时再拆分为 `commands/` 子模块。 + +--- + +## 2. GUI 命令层零测试 + +**严重级别**: LOW +**文件**: `gui/src/commands/*.rs` (8 个文件) + +**问题**: GUI 命令层是纯薄包装,无独立测试。 + +**建议**: 不值得投入 — 命令正确性由编译器类型系统保证,运行期由 57 个 core 测试 + E2E 覆盖。 + +--- + +## 已修复(本批次) + +- ~~disabled.rs 测试写入真实文件~~ → `#[cfg(test)]` 条件编译重定向到 `std::env::temp_dir()` +- ~~profiles.rs 同款问题~~ → 同上 + +--- + +_更新于: 2026-05-30 | 审查批次: v5.1 代码审查_ diff --git a/docs/code-and-architecture-review.md b/docs/code-and-architecture-review.md new file mode 100644 index 0000000..8ae629a --- /dev/null +++ b/docs/code-and-architecture-review.md @@ -0,0 +1,79 @@ +# PathEditor v5.0 代码与架构审查报告 + +## 1. 项目概览 + +PathEditor v5.0 是一个功能完善的 Windows 系统环境变量 (PATH) 编辑器,支持 GUI 与 CLI 双模式。 +技术栈选型现代化且合理: + +- **后端 / 核心逻辑**:Rust (Cargo Workspace) +- **GUI 框架**:Tauri 2.x +- **前端**:React 19 + TypeScript + Zustand + +整体项目结构清晰,职责划分明确,严格遵循了前后端分离与核心逻辑无平台依赖的设计原则。 + +## 2. 架构设计审查 + +### 2.1 Cargo Workspace 三层架构 + +项目采用了经典的 Cargo Workspace 模式,分为三层: + +- `core`: 纯 Rust 库 crate,包含所有的核心业务逻辑(注册表读写、备份、配置文件管理、路径验证与清理等)。该层**完全不依赖** Tauri 或 CLI 库,极大地提高了代码的复用性和可测试性。 +- `gui`: Tauri 桌面应用。仅作为薄包装层(Thin Wrapper),通过 `#[tauri::command]` 将 `core` 的功能暴露为 IPC 接口供前端调用。 +- `cli`: 命令行工具层。依赖 `core` 和 `clap` 库,直接提供命令行交互能力。 + +**审查结论**:架构设计非常优秀。核心逻辑解耦彻底,无论是 GUI 还是 CLI 都能复用同一套安全、经过测试的核心代码。 + +### 2.2 IPC 通信与状态同步 + +前端与 Rust 后端通过 Tauri IPC 进行通信。 + +- 所有的错误处理均通过 `Result` 返回,前端通过 `Promise` 捕获并处理,用户体验良好。 +- 针对非事务性的双写操作(如同时保存系统和用户 PATH),前端 `app-store.ts` 中使用了 `Promise.allSettled`。当发生部分成功(Partial Success)时,能正确捕获并重新加载注册表状态,避免了前端内存状态与后端注册表状态的漂移(State Drift)。 + +## 3. 后端代码审查 (Rust) + +### 3.1 核心逻辑 (`core`) + +- **安全性与健壮性**: + - 在 `registry.rs` 中,严格检查了路径字符串的 Null 字节,以及 32767 个字符的 Windows 注册表长度上限,防止缓冲区溢出或写入失败。 + - 使用了安全的 `winreg` 库进行注册表操作。 +- **FFI 调用**: + - 在 `system.rs` 中调用 Windows API(如 `ExpandEnvironmentStringsW` 和 `SendMessageTimeoutW`)时,对 `unsafe` 代码块进行了详尽的 SAFETY 注释。 + - 能够妥善处理 UTF-16 编码和解码,保留非法码点避免丢失路径信息,细节处理非常到位。 + +### 3.2 命令行工具 (`cli`) + +- **原子性与并发安全**: + - 在 CLI 的 `verify_and_save` 逻辑中,写入前会重新读取注册表并与原始状态对比。如果不一致,则拒绝写入并报错退出。这有效地防止了并发情况下的配置覆盖问题。 +- **用户体验**: + - 命令设计符合直觉,支持 `--dry-run` 预览以及 JSON 格式输出,方便与其他脚本集成。 + +## 4. 前端代码审查 (React + TypeScript) + +### 4.1 状态管理 (`app-store.ts`) + +- 使用 `Zustand` 进行全局状态管理,状态树设计合理,避免了 React Context 可能带来的不必要重渲染。 +- 实现了完善的 `UndoRedoManager`,将每一步操作抽象为 `OperationType`,支持撤销/重做功能,这对于编辑器类应用来说是核心体验的加分项。 +- `isSaving` 状态守卫有效防止了用户双击保存按钮引发的并发竞争。 + +### 4.2 UI 与逻辑分离 + +- 业务逻辑抽象到 `src/core` 目录下(如 `path-manager.ts`, `validation.ts`),UI 组件仅负责渲染和事件绑定。 +- `useAppActions.ts` 钩子巧妙地将组件层与 Store 状态操作解耦,使得组件代码极其整洁。 + +## 5. 改进建议 (Recommendations) + +虽然当前代码质量已经很高,但仍有以下几个方面可以进一步优化: + +1. **Rust FFI 维护性**: + 当前 `system.rs` 中手动声明了 `extern "system"` 函数。建议引入 `windows-rs` 或 `windows-sys` 库,这能提供微软官方维护的安全的 API 绑定,减少手动编写 FFI 签名带来的维护成本和潜在错误。 +2. **GUI 保存的并发安全 (Race Condition)**: + CLI 已经实现了保存前的二次状态比对(`verify_and_save`),但在 `gui/src/commands/registry.rs` 中,直接调用了 `save_system_paths`。如果在用户打开 GUI 修改期间,另一个进程修改了注册表,GUI 保存时可能会覆盖该修改。建议在 GUI 的 IPC 保存接口中,也引入类似 CLI 的版本校验(例如传入 `expected_original_paths` 进行比对)。 +3. **前端单元测试覆盖**: + 核心逻辑如 `undo-redo.ts` 和 `path-manager.ts` 纯函数特性明显,建议在 `tests/unit/` 下增加对这些文件的边界用例测试,确保复杂编辑操作下状态不崩溃。 +4. **长列表性能**: + 如果 PATH 环境变量条目非常多(虽然实际场景中一般在 100 条以内),React 渲染完整列表可能会有微小延迟。当前规模下无影响,但若未来考虑显示大量工具链路径扫描结果,可引入虚拟列表(Virtual List)。 + +## 总结 + +PathEditor v5.0 的代码库是一个优秀的 Rust + Tauri + React 实践范例。它具有清晰的三层架构、严格的类型和边界检查、以及良好的错误处理机制,整体架构稳健且易于长期维护。 diff --git a/docs/screenshots/.gitkeep b/docs/screenshots/.gitkeep new file mode 100644 index 0000000..a44d07a --- /dev/null +++ b/docs/screenshots/.gitkeep @@ -0,0 +1 @@ +# 截图目录 diff --git a/e2e/global.d.ts b/e2e/global.d.ts new file mode 100644 index 0000000..ce2d538 --- /dev/null +++ b/e2e/global.d.ts @@ -0,0 +1,5 @@ +interface Window { + __TAURI_INTERNALS__?: { + invoke: (cmd: string, args?: Record) => Promise; + }; +} diff --git a/e2e/tests/search-clean.spec.ts b/e2e/tests/search-clean.spec.ts index 50da331..45a7d34 100644 --- a/e2e/tests/search-clean.spec.ts +++ b/e2e/tests/search-clean.spec.ts @@ -6,22 +6,36 @@ test.beforeEach(async ({ page }) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars invoke: async (cmd, args) => { switch (cmd) { - case 'check_admin': return true; - case 'load_system_paths': return ['C:\\\\Windows', 'invalid_path', 'C:\\\\Temp']; - case 'load_user_paths': return []; - case 'load_disabled_state': return { system: [], user: [] }; - case 'save_system_paths': return undefined; - case 'save_user_paths': return undefined; - case 'save_disabled_state': return undefined; - case 'backup_registry': return ''; - case 'broadcast_env_change': return undefined; - case 'validate_path': return false; - case 'expand_env_vars': return ''; - case 'read_text_file': return ''; - case 'get_appdata_dir': return ''; - default: return undefined; + case 'check_admin': + return true; + case 'load_system_paths': + return ['C:\\\\Windows', 'invalid_path', 'C:\\\\Temp']; + case 'load_user_paths': + return []; + case 'load_disabled_state': + return { system: [], user: [] }; + case 'save_system_paths': + return undefined; + case 'save_user_paths': + return undefined; + case 'save_disabled_state': + return undefined; + case 'backup_registry': + return ''; + case 'broadcast_env_change': + return undefined; + case 'validate_path': + return false; + case 'expand_env_vars': + return ''; + case 'read_text_file': + return ''; + case 'get_appdata_dir': + return ''; + default: + return undefined; } - } + }, }; }); await page.goto('/'); diff --git a/index.html b/index.html index 6333e4f..64d0c02 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - PathEditor v4.0 + PathEditor v5.0
diff --git a/package-lock.json b/package-lock.json index 2174051..8337847 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,8 @@ "zustand": "^5.0.13" }, "devDependencies": { + "@commitlint/cli": "^21.0.2", + "@commitlint/config-conventional": "^21.0.2", "@eslint/js": "^10.0.1", "@playwright/test": "^1.60.0", "@tauri-apps/cli": "^2.11.2", @@ -29,11 +31,15 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "@vitest/coverage-v8": "^4.1.9", "eslint": "^10.3.0", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.6.0", + "husky": "^9.1.7", "jsdom": "^29.1.1", + "lint-staged": "^16.4.0", + "prettier": "^3.8.4", "typescript": "~6.0.2", "typescript-eslint": "^8.59.2", "vite": "^8.0.12", @@ -347,6 +353,16 @@ "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@bramus/specificity": { "version": "2.4.2", "resolved": "https://registry.npmmirror.com/@bramus/specificity/-/specificity-2.4.2.tgz", @@ -360,6 +376,333 @@ "specificity": "bin/cli.js" } }, + "node_modules/@commitlint/cli": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/cli/-/cli-21.0.2.tgz", + "integrity": "sha512-YMmfLbqBg+ZRvvmPhc+cilSQFrh/AgzVgCT1U/OifmUZEwPbvCtA8rN//YNaF9d5eoZphxVMGYtmwA2QgQORgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^21.0.1", + "@commitlint/lint": "^21.0.2", + "@commitlint/load": "^21.0.2", + "@commitlint/read": "^21.0.2", + "@commitlint/types": "^21.0.1", + "tinyexec": "^1.0.0", + "yargs": "^18.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/config-conventional/-/config-conventional-21.0.2.tgz", + "integrity": "sha512-P/ZRhryQmkj0Z0dY9FOoRwe3xkwJyyAdtXwt01NT2kuZttcG2CNYp1q5Ci3u+nDT2jcbJRw2kt13Czl1qKNPfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.0.1", + "conventional-changelog-conventionalcommits": "^9.2.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "21.0.1", + "resolved": "https://registry.npmmirror.com/@commitlint/config-validator/-/config-validator-21.0.1.tgz", + "integrity": "sha512-Zd2UFdndeMMaW2O96HK0tdfT4gOImUvidMpAd/pws2zZ4m1nrAZ/9b/v2JYuE8fs86GpXv9F7LNaIuCIWhY+pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.0.1", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/config-validator/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@commitlint/config-validator/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@commitlint/ensure": { + "version": "21.0.1", + "resolved": "https://registry.npmmirror.com/@commitlint/ensure/-/ensure-21.0.1.tgz", + "integrity": "sha512-jJ1037967wU7YN/xkv+iRlOBlmaOXPhPO5KQSqya6GyXzBlwuLzELBFao16DVg9dZyqmNrhewzwZ3SAibetHBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.0.1", + "es-toolkit": "^1.46.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "21.0.1", + "resolved": "https://registry.npmmirror.com/@commitlint/execute-rule/-/execute-rule-21.0.1.tgz", + "integrity": "sha512-RifH+FmImozKBE6mozhF4K3r2RRKP7SMi/Q/zLCmExtp5e05lhHOUYqGBlFBAGNHaZxU/WYw1XuugYK9jQzqnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/format": { + "version": "21.0.1", + "resolved": "https://registry.npmmirror.com/@commitlint/format/-/format-21.0.1.tgz", + "integrity": "sha512-ksmG2+cHGtuDPQQbhBbC4unwm444+6TiPw0d1bKf67hntgZqZ8E0g1MuYKUuyT5IH4IMmXZhKq22/Z3jBvtQIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.0.1", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/is-ignored/-/is-ignored-21.0.2.tgz", + "integrity": "sha512-H5z4t8PC9tUsmZ/o+EptM3Nq8sTFtskAShdcqxCoyzklW5eaVT5xbrDAET2uypzir9Vsj4ZZmBtyKjYe2XqgeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.0.1", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/is-ignored/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@commitlint/lint": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/lint/-/lint-21.0.2.tgz", + "integrity": "sha512-PnUmLYGeGLfW8oVatR9KpNxSHYAnJOEWlMZzfdeFOUq6WUrFx1fGQaWCWJqMoIll/xPM+GdfJV+tKHZVHhl0Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^21.0.2", + "@commitlint/parse": "^21.0.2", + "@commitlint/rules": "^21.0.2", + "@commitlint/types": "^21.0.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/load": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/load/-/load-21.0.2.tgz", + "integrity": "sha512-lwUE70hN0/qE/ZRROhbaX65ly/FF12DrqfReLCESo37M0OQCFAf2jRS+2tSCSORq+bm4Kdju7qNDj46uc1QzTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^21.0.1", + "@commitlint/execute-rule": "^21.0.1", + "@commitlint/resolve-extends": "^21.0.1", + "@commitlint/types": "^21.0.1", + "cosmiconfig": "^9.0.1", + "cosmiconfig-typescript-loader": "^6.1.0", + "es-toolkit": "^1.46.0", + "is-plain-obj": "^4.1.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/message": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/message/-/message-21.0.2.tgz", + "integrity": "sha512-5n4aqHGD/FNnom/D5L8i7cYtV+xjuXcBL832C3w9VglEsZzIsoHpJsvxzJ7cgiOsOdc/2jU4t5+7qMHh7GBX3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/parse": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/parse/-/parse-21.0.2.tgz", + "integrity": "sha512-QVZJhGHTm+oiuWyEKOCTQ0ZM3mfJ0eGWFeHuj7WzSKEth+UukcCHac9GD8pgdFlg/qGkFWOtyaNd1T8REgagaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^21.0.1", + "conventional-changelog-angular": "^8.2.0", + "conventional-commits-parser": "^6.3.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/read": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/read/-/read-21.0.2.tgz", + "integrity": "sha512-BtsrnLVycSSKf4Q0gMch4giCj5NNlmcbhc8ra5vONgGtP2IjRDo33bEFtr5Pm+2N+5fXGWb2MksWPrspPfdhdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^21.0.2", + "@commitlint/types": "^21.0.1", + "git-raw-commits": "^5.0.0", + "tinyexec": "^1.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "21.0.1", + "resolved": "https://registry.npmmirror.com/@commitlint/resolve-extends/-/resolve-extends-21.0.1.tgz", + "integrity": "sha512-0DhjYWL6uYrY16Efa032fYk3woGJDU4AGWiG1XXltT9AMUNYKyb5cIZU2ivbaMZ3+kKFqUjikD2cjh66Sbh/Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^21.0.1", + "@commitlint/types": "^21.0.1", + "es-toolkit": "^1.46.0", + "global-directory": "^5.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/rules": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/rules/-/rules-21.0.2.tgz", + "integrity": "sha512-k6tQ69Td7t2qUSIbik8D3TL1q3ZJpkEbV+yLogDzCRAdOxJm4ndhtBNREsLA1/puRfWvzS9eioF2w43WT+hHgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^21.0.1", + "@commitlint/message": "^21.0.2", + "@commitlint/to-lines": "^21.0.1", + "@commitlint/types": "^21.0.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "21.0.1", + "resolved": "https://registry.npmmirror.com/@commitlint/to-lines/-/to-lines-21.0.1.tgz", + "integrity": "sha512-bd1BFII7p1EQZre9Kaj+kKaMFP3cFCdt21K7DItVux9XP5WjLgJ0/Uy1pJJh9aPwVJ6SKg62PxqlZaHI8hQAXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/top-level": { + "version": "21.0.2", + "resolved": "https://registry.npmmirror.com/@commitlint/top-level/-/top-level-21.0.2.tgz", + "integrity": "sha512-s9KKM+e+mXgFeIh4n7KmOGAVT3mkJ3Fp1bBYHIK5pjeUwlEMzp/tZfb5u0Poa680AsQTXMEMRxZi1vQ9m2X5ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@commitlint/types": { + "version": "21.0.1", + "resolved": "https://registry.npmmirror.com/@commitlint/types/-/types-21.0.1.tgz", + "integrity": "sha512-4u7w8jcoCUFWhjWnASYzZHAP34OqOtuFBN87nQmFvqda03YU0T6z+yB4w0gSAMpekiRqqGk5rt+qSlW+a2vSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-commits-parser": "^6.3.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@conventional-changelog/git-client": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/@conventional-changelog/git-client/-/git-client-2.7.0.tgz", + "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/child-process-utils": "^1.0.0", + "@simple-libs/stream-utils": "^1.2.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.4.0" + }, + "peerDependenciesMeta": { + "conventional-commits-filter": { + "optional": true + }, + "conventional-commits-parser": { + "optional": true + } + } + }, + "node_modules/@conventional-changelog/git-client/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@csstools/color-helpers": { "version": "6.0.2", "resolved": "https://registry.npmmirror.com/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", @@ -1079,6 +1422,35 @@ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "license": "MIT" }, + "node_modules/@simple-libs/child-process-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@simple-libs/child-process-utils/-/child-process-utils-1.0.2.tgz", + "integrity": "sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^1.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@simple-libs/stream-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@simple-libs/stream-utils/-/stream-utils-1.2.0.tgz", + "integrity": "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -2011,17 +2383,48 @@ } } }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", + "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.9", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.9", + "vitest": "4.1.9" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-4.1.7.tgz", - "integrity": "sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==", + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.7", - "@vitest/utils": "4.1.7", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -2030,13 +2433,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.1.7.tgz", - "integrity": "sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==", + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.7", + "@vitest/spy": "4.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -2057,9 +2460,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", - "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", "dev": true, "license": "MIT", "dependencies": { @@ -2070,13 +2473,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-4.1.7.tgz", - "integrity": "sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==", + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.7", + "@vitest/utils": "4.1.9", "pathe": "^2.0.3" }, "funding": { @@ -2084,14 +2487,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-4.1.7.tgz", - "integrity": "sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==", + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.7", - "@vitest/utils": "4.1.7", + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -2100,9 +2503,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-4.1.7.tgz", - "integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", "dev": true, "license": "MIT", "funding": { @@ -2110,13 +2513,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-4.1.7.tgz", - "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.7", + "@vitest/pretty-format": "4.1.9", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -2164,6 +2567,22 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2189,6 +2608,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/aria-query": { "version": "5.3.0", "resolved": "https://registry.npmmirror.com/aria-query/-/aria-query-5.3.0.tgz", @@ -2199,6 +2625,13 @@ "dequal": "^2.0.3" } }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz", @@ -2209,6 +2642,25 @@ "node": ">=12" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.4.tgz", + "integrity": "sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", @@ -2289,6 +2741,16 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001793", "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", @@ -2320,6 +2782,143 @@ "node": ">=18" } }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmmirror.com/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "8.3.1", + "resolved": "https://registry.npmmirror.com/conventional-changelog-angular/-/conventional-changelog-angular-8.3.1.tgz", + "integrity": "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "9.3.1", + "resolved": "https://registry.npmmirror.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.1.tgz", + "integrity": "sha512-dTYtpIacRpcZgrvBYvBfArMmK2xvIpv2TaxM0/ZI5CBtNUzvF2x0t15HsbRABWprS6UPmvj+PzHVjSx4qAVKyw==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-parser": { + "version": "6.4.0", + "resolved": "https://registry.npmmirror.com/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz", + "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^1.2.0", + "meow": "^13.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2327,6 +2926,61 @@ "dev": true, "license": "MIT" }, + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.3.0", + "resolved": "https://registry.npmmirror.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", + "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "2.6.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/cosmiconfig-typescript-loader/node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2443,6 +3097,19 @@ "license": "MIT", "peer": true }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.361", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.361.tgz", @@ -2450,6 +3117,13 @@ "dev": true, "license": "ISC" }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, "node_modules/enhanced-resolve": { "version": "5.22.0", "resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz", @@ -2476,6 +3150,39 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-module-lexer": { "version": "2.1.0", "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-2.1.0.tgz", @@ -2483,6 +3190,17 @@ "dev": true, "license": "MIT" }, + "node_modules/es-toolkit": { + "version": "1.47.1", + "resolved": "https://registry.npmmirror.com/es-toolkit/-/es-toolkit-1.47.1.tgz", + "integrity": "sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", @@ -2698,6 +3416,13 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/expect-type/-/expect-type-1.3.0.tgz", @@ -2729,6 +3454,23 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", @@ -2821,6 +3563,46 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/git-raw-commits/-/git-raw-commits-5.0.1.tgz", + "integrity": "sha512-Y+csSm2GD/PCSh6Isd/WiMjNAydu0VBiG9J7EdQsNA5P9uXvLayqjmTsNlK5Gs9IhblFZqOU0yid5Il5JPoLiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@conventional-changelog/git-client": "^2.6.0", + "meow": "^13.0.0" + }, + "bin": { + "git-raw-commits": "src/cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2834,6 +3616,22 @@ "node": ">=10.13.0" } }, + "node_modules/global-directory": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/global-directory/-/global-directory-5.0.0.tgz", + "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "6.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globals": { "version": "17.6.0", "resolved": "https://registry.npmmirror.com/globals/-/globals-17.6.0.tgz", @@ -2853,6 +3651,16 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmmirror.com/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -2883,6 +3691,13 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/html-parse-stringify": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", @@ -2892,6 +3707,22 @@ "void-elements": "3.1.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmmirror.com/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/i18next": { "version": "26.2.0", "resolved": "https://registry.npmmirror.com/i18next/-/i18next-26.2.0.tgz", @@ -2939,6 +3770,33 @@ "node": ">= 4" } }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "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/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2959,6 +3817,23 @@ "node": ">=8" } }, + "node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2969,6 +3844,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", @@ -2982,6 +3873,29 @@ "node": ">=0.10.0" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -2996,6 +3910,45 @@ "dev": true, "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmmirror.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jiti": { "version": "2.7.0", "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.7.0.tgz", @@ -3012,6 +3965,29 @@ "dev": true, "license": "MIT" }, + "node_modules/js-yaml": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsdom": { "version": "29.1.1", "resolved": "https://registry.npmmirror.com/jsdom/-/jsdom-29.1.1.tgz", @@ -3083,6 +4059,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3383,6 +4366,55 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "16.4.0", + "resolved": "https://registry.npmmirror.com/lint-staged/-/lint-staged-16.4.0.tgz", + "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.3", + "listr2": "^9.0.5", + "picomatch": "^4.0.3", + "string-argv": "^0.3.2", + "tinyexec": "^1.0.4", + "yaml": "^2.8.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", @@ -3399,6 +4431,56 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3429,6 +4511,47 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmmirror.com/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mdn-data": { "version": "2.27.1", "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.27.1.tgz", @@ -3436,6 +4559,32 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmmirror.com/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/min-indent/-/min-indent-1.0.1.tgz", @@ -3515,6 +4664,22 @@ ], "license": "MIT" }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", @@ -3565,6 +4730,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "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/parse5": { "version": "8.0.1", "resolved": "https://registry.npmmirror.com/parse5/-/parse5-8.0.1.tgz", @@ -3708,6 +4905,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.8.4", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-27.5.1.tgz", @@ -3814,6 +5027,40 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rolldown": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/rolldown/-/rolldown-1.0.2.tgz", @@ -3906,6 +5153,49 @@ "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slice-ansi": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3929,6 +5219,62 @@ "dev": true, "license": "MIT" }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-3.0.0.tgz", @@ -3942,6 +5288,19 @@ "node": ">=8" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/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/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -4273,19 +5632,19 @@ } }, "node_modules/vitest": { - "version": "4.1.7", - "resolved": "https://registry.npmmirror.com/vitest/-/vitest-4.1.7.tgz", - "integrity": "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==", + "version": "4.1.9", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.7", - "@vitest/mocker": "4.1.7", - "@vitest/pretty-format": "4.1.7", - "@vitest/runner": "4.1.7", - "@vitest/snapshot": "4.1.7", - "@vitest/spy": "4.1.7", - "@vitest/utils": "4.1.7", + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -4313,12 +5672,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.7", - "@vitest/browser-preview": "4.1.7", - "@vitest/browser-webdriverio": "4.1.7", - "@vitest/coverage-istanbul": "4.1.7", - "@vitest/coverage-v8": "4.1.7", - "@vitest/ui": "4.1.7", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -4462,6 +5821,55 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -4479,6 +5887,16 @@ "dev": true, "license": "MIT" }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", @@ -4486,6 +5904,68 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "devOptional": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 790477d..e202fef 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,27 @@ "private": true, "version": "5.0.0", "type": "module", + "lint-staged": { + "*.{ts,tsx}": [ + "prettier --write", + "eslint --fix" + ], + "*.{json,md,css,html}": [ + "prettier --write" + ] + }, "scripts": { "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", + "format": "prettier --write \"src/**/*.{ts,tsx}\" \"tests/**/*.{ts,tsx}\" \"e2e/**/*.ts\"", + "format:check": "prettier --check \"src/**/*.{ts,tsx}\" \"tests/**/*.{ts,tsx}\" \"e2e/**/*.ts\"", "preview": "vite preview", "test": "vitest run", "test:watch": "vitest", - "test:e2e": "playwright test --config e2e/playwright.config.ts" + "test:coverage": "vitest run --coverage", + "test:e2e": "playwright test --config e2e/playwright.config.ts", + "prepare": "husky" }, "dependencies": { "@tailwindcss/vite": "^4.3.0", @@ -25,6 +38,8 @@ "zustand": "^5.0.13" }, "devDependencies": { + "@commitlint/cli": "^21.0.2", + "@commitlint/config-conventional": "^21.0.2", "@eslint/js": "^10.0.1", "@playwright/test": "^1.60.0", "@tauri-apps/cli": "^2.11.2", @@ -34,11 +49,15 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "@vitest/coverage-v8": "^4.1.9", "eslint": "^10.3.0", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.6.0", + "husky": "^9.1.7", "jsdom": "^29.1.1", + "lint-staged": "^16.4.0", + "prettier": "^3.8.4", "typescript": "~6.0.2", "typescript-eslint": "^8.59.2", "vite": "^8.0.12", diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..1f56390 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable-x86_64-pc-windows-gnu" diff --git a/src/components/dialogs/AnalyzeDialog.tsx b/src/components/dialogs/AnalyzeDialog.tsx index e6cf400..e70562d 100644 --- a/src/components/dialogs/AnalyzeDialog.tsx +++ b/src/components/dialogs/AnalyzeDialog.tsx @@ -66,7 +66,10 @@ export function AnalyzeDialog({ open, onClose }: Props) {
{/* 标题栏 */} -
+

{t('analyze.title')}

{(['conflicts', 'tools'] as TabType[]).map((tb) => ( @@ -88,7 +91,10 @@ export function AnalyzeDialog({ open, onClose }: Props) { {/* 内容 */}
{loading ? ( -
+
{t('analyze.scanning')}
) : tab === 'conflicts' ? ( @@ -214,5 +220,7 @@ function EmptyHint({ text }: { text: string }) { function getEnabledPaths(): string[] { const { sysPaths, userPaths } = useAppStore.getState(); - return [...sysPaths.filter((e) => e.enabled), ...userPaths.filter((e) => e.enabled)].map((e) => e.path); + return [...sysPaths.filter((e) => e.enabled), ...userPaths.filter((e) => e.enabled)].map( + (e) => e.path, + ); } diff --git a/src/components/dialogs/HelpDialog.tsx b/src/components/dialogs/HelpDialog.tsx index 7428d6e..9602216 100644 --- a/src/components/dialogs/HelpDialog.tsx +++ b/src/components/dialogs/HelpDialog.tsx @@ -1,7 +1,10 @@ import { useTranslation } from 'react-i18next'; import { Modal } from '@/components/ui/Modal'; -interface HelpDialogProps { open: boolean; onClose: () => void; } +interface HelpDialogProps { + open: boolean; + onClose: () => void; +} export function HelpDialog({ open, onClose }: HelpDialogProps) { const { t } = useTranslation(); @@ -9,9 +12,15 @@ export function HelpDialog({ open, onClose }: HelpDialogProps) { return (

{t('dialog.helpTitle')}

-
{t('help.content')}
+
+        {t('help.content')}
+      
-
diff --git a/src/components/dialogs/ImportDialog.tsx b/src/components/dialogs/ImportDialog.tsx index 7c07259..e51c350 100644 --- a/src/components/dialogs/ImportDialog.tsx +++ b/src/components/dialogs/ImportDialog.tsx @@ -9,7 +9,13 @@ interface ImportDialogProps { onCancel: () => void; } -export function ImportDialog({ open, systemCount, userCount, onSelect, onCancel }: ImportDialogProps) { +export function ImportDialog({ + open, + systemCount, + userCount, + onSelect, + onCancel, +}: ImportDialogProps) { const { t } = useTranslation(); return ( @@ -21,10 +27,40 @@ export function ImportDialog({ open, systemCount, userCount, onSelect, onCancel {userCount > 0 && `用户变量: ${userCount} 条`}

- {systemCount > 0 && } - {userCount > 0 && } - {systemCount > 0 && userCount > 0 && } - + {systemCount > 0 && ( + + )} + {userCount > 0 && ( + + )} + {systemCount > 0 && userCount > 0 && ( + + )} +
); diff --git a/src/components/dialogs/PathEditDialog.tsx b/src/components/dialogs/PathEditDialog.tsx index d31e17f..acb33af 100644 --- a/src/components/dialogs/PathEditDialog.tsx +++ b/src/components/dialogs/PathEditDialog.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { Modal } from '@/components/ui/Modal'; @@ -10,30 +10,54 @@ interface PathEditDialogProps { onCancel: () => void; } -export function PathEditDialog({ open, title, initialValue, onConfirm, onCancel }: PathEditDialogProps) { +export function PathEditDialog({ + open, + title, + initialValue, + onConfirm, + onCancel, +}: PathEditDialogProps) { const { t } = useTranslation(); const [value, setValue] = useState(initialValue); + const prevOpen = useRef(open); - // 对话框打开时重置输入值 — 此模式不会导致级联渲染 - // eslint-disable-next-line react-hooks/set-state-in-effect - useEffect(() => { if (open) setValue(initialValue); }, [open, initialValue]); + useEffect(() => { + if (open && !prevOpen.current) setValue(initialValue); + prevOpen.current = open; + }, [open, initialValue]); return (

{title}

setValue(e.target.value)} - onKeyDown={(e) => { if (e.key === 'Enter') onConfirm(value); }} + onKeyDown={(e) => { + if (e.key === 'Enter') onConfirm(value); + }} className="w-full min-w-[400px] px-3 py-2 rounded border text-sm outline-none" - style={{ backgroundColor: 'var(--app-list-bg)', color: 'var(--app-fg)', borderColor: 'var(--app-border)' }} + style={{ + backgroundColor: 'var(--app-list-bg)', + color: 'var(--app-fg)', + borderColor: 'var(--app-border)', + }} />
- -
diff --git a/src/components/dialogs/ProfileDialog.tsx b/src/components/dialogs/ProfileDialog.tsx index 59be6cb..13d4a29 100644 --- a/src/components/dialogs/ProfileDialog.tsx +++ b/src/components/dialogs/ProfileDialog.tsx @@ -65,13 +65,13 @@ export function ProfileDialog({ open, onClose }: Props) { if (!selected || !selectedData) return; if (!window.confirm(t('profile.applyConfirm', { name: selected }))) return; useAppStore.getState().replaceBothPaths( - selectedData.sys.map(e => e.path), - selectedData.user.map(e => e.path), + selectedData.sys.map((e) => e.path), + selectedData.user.map((e) => e.path), ); // 同步 disabled 状态 await invoke('save_disabled_state', { - system: selectedData.sys.filter(e => !e.enabled).map(e => e.path), - user: selectedData.user.filter(e => !e.enabled).map(e => e.path), + system: selectedData.sys.filter((e) => !e.enabled).map((e) => e.path), + user: selectedData.user.filter((e) => !e.enabled).map((e) => e.path), }); await useAppStore.getState().savePaths(); onClose(); @@ -80,7 +80,10 @@ export function ProfileDialog({ open, onClose }: Props) { const handleDelete = async (name: string) => { if (!window.confirm(`删除配置文件 "${name}"?`)) return; await invoke('delete_profile', { name }); - if (selected === name) { setSelected(null); setSelectedData(null); } + if (selected === name) { + setSelected(null); + setSelectedData(null); + } refreshProfiles(); }; @@ -95,16 +98,23 @@ export function ProfileDialog({ open, onClose }: Props) { return (
-
+

{t('profile.title')}

setNewName(e.target.value)} + onChange={(e) => setNewName(e.target.value)} placeholder={t('profile.namePlaceholder')} className="px-2 py-1 text-sm rounded border outline-none w-44" - style={{ backgroundColor: 'var(--app-list-bg)', color: 'var(--app-fg)', borderColor: 'var(--app-border)' }} + style={{ + backgroundColor: 'var(--app-list-bg)', + color: 'var(--app-fg)', + borderColor: 'var(--app-border)', + }} /> @@ -189,18 +209,32 @@ export function ProfileDialog({ open, onClose }: Props) { setRenameValue(e.target.value)} + onChange={(e) => setRenameValue(e.target.value)} className="px-2 py-1 text-xs rounded border outline-none" - style={{ backgroundColor: 'var(--app-list-bg)', color: 'var(--app-fg)', borderColor: 'var(--app-border)' }} + style={{ + backgroundColor: 'var(--app-list-bg)', + color: 'var(--app-fg)', + borderColor: 'var(--app-border)', + }} /> -
)} - - + +
)}
@@ -213,9 +247,13 @@ export function ProfileDialog({ open, onClose }: Props) { function PathSection({ title, paths }: { title: string; paths: PathEntry[] }) { return (
-
{title}
+
+ {title} +
{paths.length === 0 ? ( -
(空)
+
+ (空) +
) : (
{paths.map((e, i) => ( diff --git a/src/components/layout/AppShell.tsx b/src/components/layout/AppShell.tsx index abfb008..c41e67d 100644 --- a/src/components/layout/AppShell.tsx +++ b/src/components/layout/AppShell.tsx @@ -28,19 +28,32 @@ export function AppShell() { const setSelectedIndices = useAppStore((s) => s.setSelectedIndices); const [editDialog, setEditDialog] = useState({ - open: false, index: -1, value: '', target: TargetType.SYSTEM, + open: false, + index: -1, + value: '', + target: TargetType.SYSTEM, }); const [newDialog, setNewDialog] = useState(false); const [helpOpen, setHelpOpen] = useState(false); const [importDialog, setImportDialog] = useState({ - open: false, system: [], user: [], + open: false, + system: [], + user: [], }); const [analyzeOpen, setAnalyzeOpen] = useState(false); const [profilesOpen, setProfilesOpen] = useState(false); const actions = useAppActions(activeTab, { - editDialog, newDialog, helpOpen, importDialog, - setEditDialog, setNewDialog, setHelpOpen, setImportDialog, setAnalyzeOpen, setProfilesOpen, + editDialog, + newDialog, + helpOpen, + importDialog, + setEditDialog, + setNewDialog, + setHelpOpen, + setImportDialog, + setAnalyzeOpen, + setProfilesOpen, }); const tabConfig: { id: TabId; label: string }[] = [ @@ -50,14 +63,20 @@ export function AppShell() { ]; return ( -
+
{tabConfig.map((tab) => (
diff --git a/src/components/layout/ErrorBoundary.tsx b/src/components/layout/ErrorBoundary.tsx index 3aa9a0f..941b614 100644 --- a/src/components/layout/ErrorBoundary.tsx +++ b/src/components/layout/ErrorBoundary.tsx @@ -1,7 +1,12 @@ import { Component, type ReactNode } from 'react'; -interface Props { children: ReactNode; } -interface State { hasError: boolean; error: string; } +interface Props { + children: ReactNode; +} +interface State { + hasError: boolean; + error: string; +} export class ErrorBoundary extends Component { state: State = { hasError: false, error: '' }; @@ -18,7 +23,10 @@ export class ErrorBoundary extends Component { render() { if (this.state.hasError) { return ( -
+

应用出错

{this.state.error}

diff --git a/src/components/layout/TitleBar.tsx b/src/components/layout/TitleBar.tsx index 5a3f1dc..b2f2129 100644 --- a/src/components/layout/TitleBar.tsx +++ b/src/components/layout/TitleBar.tsx @@ -11,9 +11,7 @@ export function TitleBar() { className="flex items-center justify-between px-4 py-2 border-b select-none" style={{ borderColor: 'var(--app-border)' }} > -

- {isAdmin ? t('app.name') : t('app.nameReadonly')} -

+

{isAdmin ? t('app.name') : t('app.nameReadonly')}

v{version} ); diff --git a/src/components/path-list/MergePreview.tsx b/src/components/path-list/MergePreview.tsx index d57d32a..6f1ad40 100644 --- a/src/components/path-list/MergePreview.tsx +++ b/src/components/path-list/MergePreview.tsx @@ -56,8 +56,7 @@ export function MergePreview() { diff --git a/src/components/path-list/PathTable.tsx b/src/components/path-list/PathTable.tsx index cc198df..812e304 100644 --- a/src/components/path-list/PathTable.tsx +++ b/src/components/path-list/PathTable.tsx @@ -42,7 +42,8 @@ export function PathTable({ tabId }: PathTableProps) { const result: PathRow[] = []; for (let i = 0; i < paths.length; i++) { const p = paths[i]; - if (p.path.toLowerCase().includes(q)) result.push({ path: p.path, index: i, enabled: p.enabled }); + if (p.path.toLowerCase().includes(q)) + result.push({ path: p.path, index: i, enabled: p.enabled }); } return result; }, [paths, searchQuery]); @@ -74,15 +75,15 @@ export function PathTable({ tabId }: PathTableProps) { }); }); - return () => { cancelled = true; }; + return () => { + cancelled = true; + }; }, [paths]); // 异步展开环境变量(用于 tooltip) useEffect(() => { let cancelled = false; - const toExpand = paths.filter( - (p) => p.path.includes('%') && !expandedRef.current.has(p.path), - ); + const toExpand = paths.filter((p) => p.path.includes('%') && !expandedRef.current.has(p.path)); if (toExpand.length === 0) return; const batch = toExpand.slice(0, 20); @@ -105,7 +106,9 @@ export function PathTable({ tabId }: PathTableProps) { }); }); - return () => { cancelled = true; }; + return () => { + cancelled = true; + }; }, [paths]); // 所有路径默认有效(异步验证结果回来后再精确染色) @@ -194,7 +197,10 @@ export function PathTable({ tabId }: PathTableProps) { : 'var(--app-list-alt)', }} > - + {index + 1} diff --git a/src/components/toolbar/ToolBar.tsx b/src/components/toolbar/ToolBar.tsx index f45b412..4964054 100644 --- a/src/components/toolbar/ToolBar.tsx +++ b/src/components/toolbar/ToolBar.tsx @@ -36,12 +36,7 @@ export function ToolBar(props: ToolBarProps) {
-