diff --git a/docs/adr/0009-frontend-textlint-proofread.md b/docs/adr/0009-frontend-textlint-proofread.md new file mode 100644 index 00000000..21d9b689 --- /dev/null +++ b/docs/adr/0009-frontend-textlint-proofread.md @@ -0,0 +1,49 @@ +# ADR-0009: 職務経歴書のフロントエンド完結型 文章校正(textlint + kuromoji) + +## ステータス + +Accepted + +## コンテキスト + +職務経歴書は転職で人の目に触れる重要文書だが、DevForge には誤字脱字・表記ゆれ・冗長表現を検出する仕組みが無かった。保存前にユーザーが自分で気づけるよう、保存確認ダイアログ(`CareerDiffModal`)内で文章を校正し、指摘を一覧表示する機能を追加する。 + +制約・前提: + +- **個人情報を外部に送らない**: 職務経歴書は氏名・経歴を含む。外部 API / LLM に本文を送信しない方針(ADR-0008 のルールベース志向とも整合)。 +- **コスト**: 追加のサーバー処理・課金を避けたい。 +- **既存体験への影響最小化**: 保存フロー(`useDocumentForm.save`)の契約は変えない。 + +## 決定内容 + +**ルールベースの校正をフロントエンド完結(Web Worker)で実行する。** + +- エンジン: `@textlint/kernel` + `textlint-rule-preset-ja-technical-writing`(全23ルール)+ `textlint-rule-prh`(IT 用語の表記ゆれ辞書を同梱)。 +- 実行場所: 専用 Web Worker(`src/proofread/proofread.worker.ts`)。textlint / kuromoji 一式は動的 import で worker チャンクへ分割し、初期バンドル・初回描画から切り離す。 +- 形態素解析辞書(kuromoji): `frontend/public/kuromoji-dict/`(約18MB)に静的配信。worker から `globalThis.kuromojin.dicPath = "/kuromoji-dict"`(ルート相対)で参照。 +- UI 統合: メインスレッドは `ProofreadIssue[]` という安定インターフェースのみ知る。`useProofread` フックが保存確認ダイアログ表示中だけ校正を起動し、結果を `CareerDiffModal` 右サイドバー下部に「校正の指摘」として青系・控えめに表示する。**保存はブロックしない**(警告のみ)。 +- 辞書ロード失敗時は形態素解析依存ルール(二重助詞・冗長表現など11ルール)を除外し、prh + 非依存ルールで継続する(グレースフルデグラデーション)。 + +## 代替案 + +- **LLM / 外部校正 API**: 精度は高いが個人情報の外部送信・コスト・レイテンシで不採用(ADR-0008 の方針に反する)。 +- **バックエンド(Python)で textlint 相当を実行**: Node ランタイム追加 or Python 形態素解析の導入が必要でインフラ複雑化。本文をサーバーに送る必要も無いためフロント完結を優先。 +- **prh 単体 + 自前正規表現のみ(kuromoji 無し)**: リポジトリ肥大ゼロ・軽量だが、二重助詞・冗長表現などの文法系チェックが落ちる。フォールバック経路としては内包するが、第一選択は全プリセットとした。 + +## トレードオフ・既知のリスク + +- **リポジトリ肥大**: kuromoji 辞書 約18MB を `public/` にコミットするため git 履歴が恒久的に増える(ユーザー承認済みのトレードオフ)。 +- **初回ロード遅延**: 初回校正時に辞書(数MB)を fetch するため、最初の指摘表示まで数秒かかる。以降は worker 内でキャッシュ。 +- **ブラウザ統合の脆さ**: textlint/kuromoji は Node 前提のため、worker で `window` / `process`(`cwd`/`nextTick` 等)の最小ポリフィル、node 組み込み(`path`/`os`/`assert`)のブラウザ実装エイリアス、辞書 `.gz` を `Content-Encoding: gzip` させない配信(dev: Vite プラグイン / prod: `public/_headers`)が必要。これらは `src/proofread/worker-env-polyfill.ts`・`vite.config.ts`・`public/_headers` に集約しコメントで明示した。 +- **辞書 `.gz` の二重展開**: サーバーが `.gz` を gzip 転送エンコーディング扱いすると、ブラウザが自動展開して kuromoji の再 gunzip が失敗する。生バイト配信を強制している。 + +## 将来の移行条件 + +- リポジトリ肥大が問題化した場合: 辞書を CDN(jsDelivr 等)配信へ切り替える、または kuromoji 依存ルールを外して辞書同梱をやめる(フォールバック構成へ)。 +- 校正精度を上げたい場合: prh 辞書の拡充、もしくは(個人情報の扱いを整理した上で)サーバーサイド校正の再検討。 + +## 関連リンク + +- 実装: `frontend/src/proofread/`・`frontend/src/hooks/career/useProofread.ts`・`frontend/src/components/forms/CareerDiffModal.tsx` +- 関連 ADR: ADR-0008(ルールベース設計への移行) +- 参考: textlint / textlint-rule-preset-ja-technical-writing / kuromoji.js diff --git a/frontend/e2e/career-proofread.spec.ts b/frontend/e2e/career-proofread.spec.ts new file mode 100644 index 00000000..070cf586 --- /dev/null +++ b/frontend/e2e/career-proofread.spec.ts @@ -0,0 +1,73 @@ +import { test, expect, type Page } from "@playwright/test"; +import { setupAuth, waitForAuthenticatedLayout } from "./helpers/auth"; + +/** + * 職務経歴書 保存時の文章校正(誤字脱字・表記ゆれ)E2E。 + * + * 検証: + * - 保存確認ダイアログ(左右 diff モーダル)に「校正の指摘」セクションが出る。 + * - 自己PR の表記ゆれ("javascript" → "JavaScript")が prh で実際に検出され、 + * worker(textlint + kuromoji 辞書ロード)経由で指摘が画面に出る。 + * + * 校正はフロント完結(API なし)なので backend モック不要。worker が public/kuromoji-dict/ + * から辞書をロードするため、指摘表示には余裕を持った待機を取る。 + */ +async function setupResumeApi(page: Page) { + const baseResume = { + id: "resume-1", + full_name: "山田 太郎", + career_summary: "サマリー", + // 表記ゆれ(javascript)を含む自己PR。 + self_pr: "私はjavascriptが得意です。", + experiences: [], + qualifications: [], + }; + + await page.route("**/api/master-data/qualification", (route) => + route.fulfill({ status: 200, contentType: "application/json", body: "[]" }), + ); + await page.route("**/api/master-data/technology-stack", (route) => + route.fulfill({ status: 200, contentType: "application/json", body: "[]" }), + ); + await page.route("**/api/resumes/preview", (route) => + route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ html: "
preview
", css: "" }), + }), + ); + await page.route("**/api/resumes/latest", (route) => + route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify(baseResume), + }), + ); +} + +test.describe("職務経歴書 保存時の文章校正", () => { + test.beforeEach(async ({ page }) => { + await setupAuth(page); + await setupResumeApi(page); + }); + + test("保存確認ダイアログに校正の指摘(表記ゆれ)が表示される", async ({ page }) => { + await page.goto("/career"); + await waitForAuthenticatedLayout(page); + + // 変更を作って確認ダイアログを開く(氏名を編集)。 + await page.getByPlaceholder("例: 山田 太郎").fill("佐藤 花子"); + await page.getByRole("button", { name: /更新する|保存する/ }).click(); + + // ダイアログと統合レビュー一覧(変更点+校正)が出る。 + await expect(page.getByRole("dialog", { name: "変更内容の確認" })).toBeVisible(); + await expect(page.getByText("変更点・校正", { exact: true })).toBeVisible(); + + // prh による表記ゆれ指摘(javascript => JavaScript)が worker 経由で表示される。 + // 辞書ロードを含むため待機時間を長めに取る。 + await expect(page.getByText(/JavaScript/)).toBeVisible({ timeout: 30000 }); + + // 校正があっても保存はブロックされない(「この内容で保存」が押せる)。 + await expect(page.getByRole("button", { name: "この内容で保存" })).toBeEnabled(); + }); +}); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1995faa9..5c23e6c3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,15 +9,20 @@ "version": "0.1.0", "dependencies": { "@reduxjs/toolkit": "^2.11.2", + "@textlint/kernel": "^15.7.1", + "@textlint/textlint-plugin-text": "^15.7.1", "dompurify": "^3.4.7", "marked": "^17.0.4", + "prh": "^6.0.6", "react": "^18.3.1", "react-dom": "^18.3.1", "react-pdf": "^9.2.1", "react-redux": "^9.2.0", "react-router-dom": "^7.13.1", "recharts": "^3.8.0", - "redux-persist": "^6.0.0" + "redux-persist": "^6.0.0", + "textlint-rule-preset-ja-technical-writing": "^12.0.2", + "textlint-rule-prh": "^6.1.0" }, "devDependencies": { "@eslint/js": "^9.39.4", @@ -25,11 +30,13 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@textlint/types": "^15.7.1", "@types/node": "^25.5.2", "@types/react": "^18.3.15", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react": "^4.4.1", "@vitest/coverage-v8": "^4.1.2", + "assert": "^2.1.0", "concurrently": "^9.2.1", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", @@ -40,6 +47,8 @@ "jsdom": "^29.0.1", "msw": "^2.13.2", "openapi-typescript": "^7.13.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", "playwright": "^1.56.0", "prettier": "^3.8.1", "typescript": "^5.7.2", @@ -263,7 +272,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -273,7 +281,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -307,7 +314,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -399,7 +405,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -2002,6 +2007,55 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kvs/env": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@kvs/env/-/env-2.2.2.tgz", + "integrity": "sha512-tvy6eb1IHiQWqgSBjOxJp+gQ8wI/1bT5pWKU0VJL9d8SwAflOpN9777wQ3RY3jUtEUpcQOUtxrxcrMs9VYiNBw==", + "license": "MIT", + "dependencies": { + "@kvs/indexeddb": "^2.2.2", + "@kvs/node-localstorage": "^2.2.2", + "@kvs/storage": "^2.2.2", + "@kvs/types": "^2.2.2" + } + }, + "node_modules/@kvs/indexeddb": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@kvs/indexeddb/-/indexeddb-2.2.2.tgz", + "integrity": "sha512-h9Fom6YvbRzMHhBLZKdNNJ/bgla0aBbmVBzUBLUoeEwT3C16Yx5eGA+spUQ69ZoRbsArZufX84qX/wRbyvjtrg==", + "license": "MIT", + "dependencies": { + "@kvs/storage": "^2.2.2", + "@kvs/types": "^2.2.2" + } + }, + "node_modules/@kvs/node-localstorage": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@kvs/node-localstorage/-/node-localstorage-2.2.2.tgz", + "integrity": "sha512-e6r2CBWAQznaLEAmYSNNPGXUkSRP+yffSZNJYfgR4II8vjDFtGj1gByo2yk7pQsRiiId6IZ5dwDl1Tib3bNaqw==", + "license": "MIT", + "dependencies": { + "@kvs/storage": "^2.2.2", + "@kvs/types": "^2.2.2", + "app-root-path": "^3.1.0", + "node-localstorage": "^2.1.6" + } + }, + "node_modules/@kvs/storage": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@kvs/storage/-/storage-2.2.2.tgz", + "integrity": "sha512-jThnhLTcT0w1SHzhr/PFTzzkKl+V3J6X07NyARceT02mIu5+tBWwtUhS68UNOaD7CTQ07rMFgb5UHoolies94g==", + "license": "MIT", + "dependencies": { + "@kvs/types": "^2.2.2" + } + }, + "node_modules/@kvs/types": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@kvs/types/-/types-2.2.2.tgz", + "integrity": "sha512-5lmBuah+wOdypBf0O9t6BoHrnq5hX5MlhEPTDPBNKN38ayQwVc5gYgJOBR3Dg4EF7OwL+1c7JNtWXQEJXXVXlg==", + "license": "MIT" + }, "node_modules/@mswjs/interceptors": { "version": "0.41.3", "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.3.tgz", @@ -2694,6 +2748,176 @@ "@testing-library/dom": ">=7.21.4" } }, + "node_modules/@textlint-rule/textlint-rule-no-invalid-control-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@textlint-rule/textlint-rule-no-invalid-control-character/-/textlint-rule-no-invalid-control-character-3.0.0.tgz", + "integrity": "sha512-2o9n4z49ntSPtJPlcJtxakyB4dAg2MKSvR9ZCZEHjye0ee27oWYzK6yHz2HjsXQqt9VeCwxNHDOIGIx2CQX0Dw==", + "license": "MIT" + }, + "node_modules/@textlint-rule/textlint-rule-no-unmatched-pair": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@textlint-rule/textlint-rule-no-unmatched-pair/-/textlint-rule-no-unmatched-pair-2.0.4.tgz", + "integrity": "sha512-g9Ge1xUV9xJy8T7nuutF/2J6Cg2mmPx4gKsC3dCdxVxuL0wMqOOnAi8l6psFpAQ5UFtQuAzwkdclrehPtBT5tg==", + "license": "MIT", + "dependencies": { + "sentence-splitter": "^5.0.0", + "textlint-rule-helper": "^2.3.1" + } + }, + "node_modules/@textlint/ast-node-types": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.7.1.tgz", + "integrity": "sha512-Wii5UgUKFEh9Uv6wbq1zr4/Kf+dtjiUuzPrrXzKp8H+ifkvKNzi23V4Nz+6wVyHQn5T28AFuc8VH8OtzvGYecA==", + "license": "MIT" + }, + "node_modules/@textlint/ast-tester": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-tester/-/ast-tester-15.7.1.tgz", + "integrity": "sha512-0CZWFKB7D21y8LA4Dv5irOX1/iGDGwM4OTaW7PxJpfRhXCL40uMOhS+P+1bjFmpSkM/DF/5HPRph0E744iJobw==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.7.1", + "debug": "^4.4.3" + } + }, + "node_modules/@textlint/ast-traverse": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-traverse/-/ast-traverse-15.7.1.tgz", + "integrity": "sha512-tFgFiSbh6fdQo7MF4FYQoQBHqM8BoTEfvubGXm7Xi65QRYefNz+iuXYaoyto6OlMj5M95u9Gk/Ni7577rZ8uow==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.7.1" + } + }, + "node_modules/@textlint/feature-flag": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/feature-flag/-/feature-flag-15.7.1.tgz", + "integrity": "sha512-ZFIJ2edV7K04UJ7/7ptvL61vs54MHYzDaIfTW+vaXwq5KDeCD2QyjsKt+TbOHQ8n8sW6fO171n4p0gwRo01Ojg==", + "license": "MIT" + }, + "node_modules/@textlint/kernel": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/kernel/-/kernel-15.7.1.tgz", + "integrity": "sha512-OGghiMbXLD3ULHedZYP1B+A8Bj4snlCatzsOdz0M8q0v4I79NdcamWt/5GYmbp6AOQg3HBQG8+9V+0H+do19mw==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.7.1", + "@textlint/ast-tester": "15.7.1", + "@textlint/ast-traverse": "15.7.1", + "@textlint/feature-flag": "15.7.1", + "@textlint/source-code-fixer": "15.7.1", + "@textlint/types": "15.7.1", + "@textlint/utils": "15.7.1", + "debug": "^4.4.3", + "fast-equals": "^4.0.3", + "structured-source": "^4.0.0" + } + }, + "node_modules/@textlint/markdown-to-ast": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-13.4.1.tgz", + "integrity": "sha512-jUa5bTNmxjEgfCXW4xfn7eSJqzUXyNKiIDWLKtI4MUKRNhT3adEaa/NuQl0Mii3Hu3HraZR7hYhRHLh+eeM43w==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^13.4.1", + "debug": "^4.3.4", + "mdast-util-gfm-autolink-literal": "^0.1.3", + "remark-footnotes": "^3.0.0", + "remark-frontmatter": "^3.0.0", + "remark-gfm": "^1.0.0", + "remark-parse": "^9.0.0", + "traverse": "^0.6.7", + "unified": "^9.2.2" + } + }, + "node_modules/@textlint/markdown-to-ast/node_modules/@textlint/ast-node-types": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-13.4.1.tgz", + "integrity": "sha512-qrZyhCh8Ekk6nwArx3BROybm9BnX6vF7VcZbijetV/OM3yfS4rTYhoMWISmhVEP2H2re0CtWEyMl/XF+WdvVLQ==", + "license": "MIT" + }, + "node_modules/@textlint/module-interop": { + "version": "14.8.4", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-14.8.4.tgz", + "integrity": "sha512-1LdPYLAVpa27NOt6EqvuFO99s4XLB0c19Hw9xKSG6xQ1K82nUEyuWhzTQKb3KJ5Qx7qj14JlXZLfnEuL6A16Bw==", + "license": "MIT" + }, + "node_modules/@textlint/regexp-string-matcher": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@textlint/regexp-string-matcher/-/regexp-string-matcher-1.1.1.tgz", + "integrity": "sha512-rrNUCKGKYBrZALotSF8D5A8xD05VHX6kxv0BP805Ig2M73Ha6LK+de31+ZocGm4CO+sikVFYyMCPPJhp7bCXcw==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0", + "execall": "^2.0.0", + "lodash.sortby": "^4.7.0", + "lodash.uniq": "^4.5.0", + "lodash.uniqwith": "^4.5.0", + "to-regex": "^3.0.2" + } + }, + "node_modules/@textlint/regexp-string-matcher/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/source-code-fixer": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/source-code-fixer/-/source-code-fixer-15.7.1.tgz", + "integrity": "sha512-Z8ZfQQbVH2GIUMzSGEQWKKnAFCH+mbQtw5ipigFHExUImx2RC2ppaR1m8ZAy7SYgbXGhvfkPKZ4ndEmVWTs5Mg==", + "license": "MIT", + "dependencies": { + "@textlint/types": "15.7.1", + "debug": "^4.4.3" + } + }, + "node_modules/@textlint/text-to-ast": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/text-to-ast/-/text-to-ast-15.7.1.tgz", + "integrity": "sha512-W6AYCOcEAtw9hs0u69+Tte8hmWaLKYGdo3yBxgOpl20Q6AOkxxEaG305Nr5rgbO6caWJWkR/t2WxBkZzm3KG0A==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.7.1" + } + }, + "node_modules/@textlint/textlint-plugin-markdown": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-markdown/-/textlint-plugin-markdown-13.4.1.tgz", + "integrity": "sha512-OcLkFKYmbYeGJ0kj2487qcicCYTiE2vJLwfPcUDJrNoMYak5JtvHJfWffck8gON2mEM00DPkHH0UdxZpFjDfeg==", + "license": "MIT", + "dependencies": { + "@textlint/markdown-to-ast": "^13.4.1" + } + }, + "node_modules/@textlint/textlint-plugin-text": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-text/-/textlint-plugin-text-15.7.1.tgz", + "integrity": "sha512-krU0KiDmG2LrESF3LchgfbSwclB/8I2itA4uzSY9Tln3miaWGKzUpLu00bQtvua0f2Ux7tsLnSmwAgGFf9gERA==", + "license": "MIT", + "dependencies": { + "@textlint/text-to-ast": "15.7.1", + "@textlint/types": "15.7.1" + } + }, + "node_modules/@textlint/types": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.7.1.tgz", + "integrity": "sha512-Vye/GmFNBTgVzZFtIFJTmLB+s2A7oIADxNG6r9UhfPuY+Czv0z5G3xeyFZZudPlfxURsKUyPIU5XsjOFqVp33A==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.7.1" + } + }, + "node_modules/@textlint/utils": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@textlint/utils/-/utils-15.7.1.tgz", + "integrity": "sha512-+q5Z5fsNk/ixDY5D70ZCQungr7ppzBAAhmi207qDBzSBFeA5MM2ASGwMjPc5aMJ/3DvonI/01B3UIgbpVgIXVA==", + "license": "MIT" + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -2852,6 +3076,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mdast": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, "node_modules/@types/node": { "version": "25.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", @@ -2904,6 +3137,12 @@ "license": "MIT", "optional": true }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, "node_modules/@types/use-sync-external-store": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", @@ -3434,6 +3673,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/analyze-desumasu-dearu": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/analyze-desumasu-dearu/-/analyze-desumasu-dearu-5.0.2.tgz", + "integrity": "sha512-3PUxFk790GpQkME//hwiJellbtKMiAFX/CyA93etmAo5FujJ+5GKVXW+NU9v2MfF07iWcXsrNMbGW5/vVpqWwA==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -3470,11 +3718,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, "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/aria-query": { @@ -3487,6 +3743,57 @@ "dequal": "^2.0.3" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -3497,6 +3804,15 @@ "node": ">=12" } }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ast-v8-to-istanbul": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", @@ -3516,6 +3832,49 @@ "dev": true, "license": "MIT" }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3611,6 +3970,12 @@ "url": "https://opencollective.com/express" } }, + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "license": "BSD-2-Clause" + }, "node_modules/brace-expansion": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", @@ -3704,11 +4069,28 @@ "node": ">= 0.8" } }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3722,7 +4104,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -3781,6 +4162,16 @@ "node": "^18.12.0 || >= 20.9.0" } }, + "node_modules/ccount": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", + "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -3815,6 +4206,51 @@ "dev": true, "license": "MIT" }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/check-ends-with-period": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/check-ends-with-period/-/check-ends-with-period-3.0.2.tgz", + "integrity": "sha512-/Bw+avucqqZ7PjKCVDod1QDGyZjo7Ht2701pdgcpTXzK5jI73/OUh3VR+m18jNUoJx5DSOUv0AxELZF7FYtcDA==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.1.0" + } + }, + "node_modules/check-ends-with-period/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", @@ -3865,6 +4301,18 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clone-regexp": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", + "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==", + "license": "MIT", + "dependencies": { + "is-regexp": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -3901,6 +4349,31 @@ "dev": true, "license": "MIT" }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/commandpost": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", + "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4181,22 +4654,72 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": ">=6.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decimal.js": { @@ -4245,6 +4768,53 @@ "dev": true, "license": "MIT" }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -4274,6 +4844,15 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dom-accessibility-api": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", @@ -4291,11 +4870,16 @@ "@types/trusted-types": "^2.0.7" } }, + "node_modules/doublearray": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/doublearray/-/doublearray-0.0.2.tgz", + "integrity": "sha512-aw55FtZzT6AmiamEj2kvmR6BuFqvYgKZUkfQ7teqVRNqD5UE0rw8IeW/3gieHNKQ5sPuDKlljWEn4bzv5+1bHw==", + "license": "MIT" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -4370,11 +4954,78 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4384,7 +5035,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4401,7 +5051,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -4410,6 +5059,38 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-toolkit": { "version": "1.45.1", "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz", @@ -4483,7 +5164,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -4646,6 +5326,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", @@ -4718,6 +5411,18 @@ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, + "node_modules/execall": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", + "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", + "license": "MIT", + "dependencies": { + "clone-regexp": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -4792,6 +5497,25 @@ "node": ">= 0.6" } }, + "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/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "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", @@ -4799,6 +5523,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-equals": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz", + "integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==", + "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", @@ -4813,6 +5543,19 @@ "dev": true, "license": "MIT" }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -4938,6 +5681,29 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4984,12 +5750,49 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5014,7 +5817,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -5039,7 +5841,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -5049,6 +5850,23 @@ "node": ">= 0.4" } }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -5082,11 +5900,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5095,6 +5928,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, "node_modules/graphql": { "version": "16.13.2", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.13.2.tgz", @@ -5105,6 +5944,18 @@ "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -5115,33 +5966,116 @@ "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==", - "dev": true, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", - "dev": true, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "dunder-proto": "^1.0.0" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/headers-polyfill": { + "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/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz", + "integrity": "sha512-gOc8UB99F6eWVWFtM9jUikjN7QkWxB3nY0df5Z0Zq1/Nkwl5V4hAAsl0tmwlgWl/1shlTF8DnNYLO8X6wRV9pA==", + "license": "MIT", + "dependencies": { + "ccount": "^1.0.3", + "hastscript": "^5.0.0", + "property-information": "^5.0.0", + "web-namespaces": "^1.1.2", + "xtend": "^4.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.2.tgz", + "integrity": "sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==", + "license": "MIT", + "dependencies": { + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/headers-polyfill": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", @@ -5339,7 +6273,6 @@ "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" @@ -5382,6 +6315,20 @@ "license": "ISC", "optional": true }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -5401,170 +6348,692 @@ "node": ">= 0.10" } }, - "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, + "node_modules/is-accessor-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.2.tgz", + "integrity": "sha512-AIbwAcazqP3R65dGvqk1V+a+vE5Fg1yu/ZKMOiBWSUIXXiwQkYmXQcVa2O0nh0tSDKDFKxG2mY7dB1Sr4hEP1g==", "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "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==", - "dev": true, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", "license": "MIT", - "engines": { - "node": ">=8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-node-process": { + "node_modules/is-arguments": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", - "dev": true, - "license": "MIT" - }, - "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==", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, "engines": { - "node": ">=0.12.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true, - "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/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "license": "MIT", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" + "has-bigints": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "license": "MIT", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "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", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "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/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "hasown": "^2.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 0.4" } }, - "node_modules/jsdom": { - "version": "29.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.1.tgz", - "integrity": "sha512-z6JOK5gRO7aMybVq/y/MlIpKh8JIi68FBKMUtKkK2KH/wMSRlCxQ682d08LB9fYXplyY/UXG8P4XXTScmdjApg==", - "dev": true, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^5.0.1", - "@asamuzakjp/dom-selector": "^7.0.3", - "@bramus/specificity": "^2.4.2", - "@csstools/css-syntax-patches-for-csstree": "^1.1.1", - "@exodus/bytes": "^1.15.0", - "css-tree": "^3.2.1", - "data-urls": "^7.0.0", - "decimal.js": "^10.6.0", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.4.tgz", + "integrity": "sha512-bv5z95W0dDtLfKwDfkTNxaRxmISBD3eQBKJeVxv2AQ7MjuUnDNG7cIQqvFtMOUYhsILWHhMayWdoGqNqYYYjww==", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.2", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true, + "license": "MIT" + }, + "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-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz", + "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "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/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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/japanese-numerals-to-number": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/japanese-numerals-to-number/-/japanese-numerals-to-number-1.0.2.tgz", + "integrity": "sha512-rgs/V7G8Gfy8Z4XtnVBYXzWMAb9oUWp1pDdRmwHmh0hcjcy1kOu+DOpC5rwoHUAN4TqANwb7WD6z5W2v7v7PQQ==", + "license": "MIT" + }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.1.tgz", + "integrity": "sha512-z6JOK5gRO7aMybVq/y/MlIpKh8JIi68FBKMUtKkK2KH/wMSRlCxQ682d08LB9fYXplyY/UXG8P4XXTScmdjApg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.0.1", + "@asamuzakjp/dom-selector": "^7.0.3", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.1", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.7", @@ -5668,6 +7137,28 @@ "node": ">=6" } }, + "node_modules/kuromoji": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/kuromoji/-/kuromoji-0.1.2.tgz", + "integrity": "sha512-V0dUf+C2LpcPEXhoHLMAop/bOht16Dyr+mDiIE39yX3vqau7p80De/koFqpiTcL1zzdZlc3xuHZ8u5gjYRfFaQ==", + "license": "Apache-2.0", + "dependencies": { + "async": "^2.0.1", + "doublearray": "0.0.2", + "zlibjs": "^0.3.1" + } + }, + "node_modules/kuromojin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/kuromojin/-/kuromojin-3.0.1.tgz", + "integrity": "sha512-E4rLmbTid8ZGH8Fw421UXvfgCe0IXGFKhUw/IosBVW6ootxVGKGbtb0UPQAvPswgsXX/8UuPiE+amz1NN11Uzg==", + "license": "MIT", + "dependencies": { + "@kvs/env": "^2.1.3", + "kuromoji": "0.1.2", + "lru_map": "^0.4.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5698,6 +7189,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5705,6 +7202,34 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/lodash.uniqwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", + "integrity": "sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -5717,6 +7242,12 @@ "loose-envify": "cli.js" } }, + "node_modules/lru_map": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.4.1.tgz", + "integrity": "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -5807,6 +7338,19 @@ "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" } }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/marked": { "version": "17.0.4", "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.4.tgz", @@ -5819,16 +7363,183 @@ "node": ">= 20" } }, + "node_modules/match-index": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/match-index/-/match-index-1.0.3.tgz", + "integrity": "sha512-1XjyBWqCvEFFUDW/MPv0RwbITRD4xQXOvKoPYtLDq8IdZTfdF/cQSo5Yn4qvhfSSZgjgkTFsqJD2wOUG4ovV8Q==", + "license": "MIT", + "dependencies": { + "regexp.prototype.flags": "^1.1.1" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, + "node_modules/mdast-util-find-and-replace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz", + "integrity": "sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^4.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-footnote": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/mdast-util-footnote/-/mdast-util-footnote-0.1.7.tgz", + "integrity": "sha512-QxNdO8qSxqbO2e3m09KwDKfWiLgqyCurdWTQ198NpbZ2hxntdc+VKS4fDJCmNWbAroUdYnSthu+XbZ8ovh8C3w==", + "license": "MIT", + "dependencies": { + "mdast-util-to-markdown": "^0.6.0", + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", + "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-string": "^2.0.0", + "micromark": "~2.11.0", + "parse-entities": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-0.2.0.tgz", + "integrity": "sha512-FHKL4w4S5fdt1KjJCwB0178WJ0evnyyQr5kXTM3wrOVpytD0hrkvd+AOOjU9Td8onOejCkmZ+HQRT3CZ3coHHQ==", + "license": "MIT", + "dependencies": { + "micromark-extension-frontmatter": "^0.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz", + "integrity": "sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ==", + "license": "MIT", + "dependencies": { + "mdast-util-gfm-autolink-literal": "^0.1.0", + "mdast-util-gfm-strikethrough": "^0.2.0", + "mdast-util-gfm-table": "^0.1.0", + "mdast-util-gfm-task-list-item": "^0.1.0", + "mdast-util-to-markdown": "^0.6.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz", + "integrity": "sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A==", + "license": "MIT", + "dependencies": { + "ccount": "^1.0.0", + "mdast-util-find-and-replace": "^1.1.0", + "micromark": "^2.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz", + "integrity": "sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA==", + "license": "MIT", + "dependencies": { + "mdast-util-to-markdown": "^0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz", + "integrity": "sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ==", + "license": "MIT", + "dependencies": { + "markdown-table": "^2.0.0", + "mdast-util-to-markdown": "~0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz", + "integrity": "sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A==", + "license": "MIT", + "dependencies": { + "mdast-util-to-markdown": "~0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdn-data": { "version": "2.27.1", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", @@ -5876,6 +7587,132 @@ } } }, + "node_modules/micromark": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", + "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, + "node_modules/micromark-extension-footnote": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/micromark-extension-footnote/-/micromark-extension-footnote-0.3.2.tgz", + "integrity": "sha512-gr/BeIxbIWQoUm02cIfK7mdMZ/fbroRpLsck4kvFtjbzP4yi+OPVbnukTc/zy0i7spC2xYE/dbX1Sur8BEDJsQ==", + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-0.2.2.tgz", + "integrity": "sha512-q6nPLFCMTLtfsctAuS0Xh4vaolxSFUWUWR6PZSrXXiRy+SANGllpcqdXFv2z07l0Xz/6Hl40hK0ffNCJPH2n1A==", + "license": "MIT", + "dependencies": { + "fault": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz", + "integrity": "sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A==", + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0", + "micromark-extension-gfm-autolink-literal": "~0.5.0", + "micromark-extension-gfm-strikethrough": "~0.6.5", + "micromark-extension-gfm-table": "~0.4.0", + "micromark-extension-gfm-tagfilter": "~0.3.0", + "micromark-extension-gfm-task-list-item": "~0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz", + "integrity": "sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw==", + "license": "MIT", + "dependencies": { + "micromark": "~2.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz", + "integrity": "sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw==", + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz", + "integrity": "sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA==", + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz", + "integrity": "sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz", + "integrity": "sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ==", + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -6004,11 +7841,44 @@ "license": "MIT", "optional": true }, + "node_modules/moji": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moji/-/moji-0.5.1.tgz", + "integrity": "sha512-xYylXOjBS9mE/d690InK3Y74NpE0El0TmAKDmKJveWk9jds/0Tl7MQP4yhavS0U64diEq+5ey2905nhCpIHE+Q==", + "license": "MIT", + "dependencies": { + "object-assign": "^3.0.0" + } + }, + "node_modules/morpheme-match": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/morpheme-match/-/morpheme-match-2.0.4.tgz", + "integrity": "sha512-C3U5g2h47dpztGVePLA8w2O1aQEvuJORwIcahWaCG91YPrq+0u7qcPsF9Nqqe8noFvHwgO7b2EEk3iPnYuGTew==", + "license": "MIT" + }, + "node_modules/morpheme-match-all": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/morpheme-match-all/-/morpheme-match-all-2.0.5.tgz", + "integrity": "sha512-a6B6Nh4AhjMoEzVz8NOT5M9f3XwFVPM395gqnFNUXG/KTqQFTb9qM5JJFHJe+SvWfRVXTZSejyXNt+h+jmHUuQ==", + "license": "MIT", + "dependencies": { + "morpheme-match": "^2.0.4" + } + }, + "node_modules/morpheme-match-textlint": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/morpheme-match-textlint/-/morpheme-match-textlint-2.0.6.tgz", + "integrity": "sha512-CX+iQaUjjPMLvas+hZ8zg6Csxx5j1RLaytr+5w6lpBi/oTEV2pv6sgW5Vu3+pNJHbYcaqcuofQZsKocMNUNH8g==", + "license": "MIT", + "dependencies": { + "morpheme-match": "^2.0.4", + "morpheme-match-all": "^2.0.5" + } + }, "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==", - "dev": true, "license": "MIT" }, "node_modules/msw": { @@ -6142,6 +8012,18 @@ "license": "MIT", "optional": true }, + "node_modules/node-localstorage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-2.2.1.tgz", + "integrity": "sha512-vv8fJuOUCCvSPjDjBLlMqYMHob4aGjkmrkaE42/mZr0VT+ZAU10jRF8oTnX9+pgU9/vYJ8P7YT3Vd6ajkmzSCw==", + "license": "MIT", + "dependencies": { + "write-file-atomic": "^1.1.4" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", @@ -6149,12 +8031,66 @@ "dev": true, "license": "MIT" }, + "node_modules/object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", + "license": "MIT", + "engines": { + "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/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, "engines": { "node": ">= 0.4" }, @@ -6248,6 +8184,13 @@ "node": ">= 0.8.0" } }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true, + "license": "MIT" + }, "node_modules/outvariant": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", @@ -6255,6 +8198,23 @@ "dev": true, "license": "MIT" }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -6300,6 +8260,24 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "license": "MIT", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/parse-json": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", @@ -6354,6 +8332,13 @@ "node": ">= 0.8" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6488,6 +8473,15 @@ "node": ">=4" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -6609,6 +8603,36 @@ "license": "MIT", "peer": true }, + "node_modules/prh": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/prh/-/prh-6.0.6.tgz", + "integrity": "sha512-WJ7aaIa37vwHYg5sa1VaqykJiO/6AEkbQOTEnp/52XDXnbMcBPY1++oeV5trjFrLbiTqJY5nO5BaR/MR5ioJHw==", + "license": "MIT", + "dependencies": { + "commander": "^14.0.3", + "diff": "^9.0.0", + "js-yaml": "^4.1.0" + }, + "bin": { + "prh": "bin/prh" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -6927,6 +8951,152 @@ "redux": "^5.0.0" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regx": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/regx/-/regx-1.0.4.tgz", + "integrity": "sha512-Z/5ochRUyD5TkJgFq+66ajKePlj6KzpSLfDO2lOLOLu7E82xAjNux0m8mx1DAXBj5ECHiRCBWoqL25b4lkwcgw==", + "license": "MIT" + }, + "node_modules/rehype-parse": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-6.0.2.tgz", + "integrity": "sha512-0S3CpvpTAgGmnz8kiCyFLGuW5yA4OQhyNTm/nwPopZ7+PI11WnGl1TTWTGv/2hPEe/g2jRLlhVVSsoDH8waRug==", + "license": "MIT", + "dependencies": { + "hast-util-from-parse5": "^5.0.0", + "parse5": "^5.0.0", + "xtend": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-parse/node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "license": "MIT" + }, + "node_modules/remark-footnotes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-3.0.0.tgz", + "integrity": "sha512-ZssAvH9FjGYlJ/PBVKdSmfyPc3Cz4rTWgZLI4iE/SX8Nt5l3o3oEjv3wwG5VD7xOjktzdwp5coac+kJV9l4jgg==", + "license": "MIT", + "dependencies": { + "mdast-util-footnote": "^0.1.0", + "micromark-extension-footnote": "^0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-frontmatter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-3.0.0.tgz", + "integrity": "sha512-mSuDd3svCHs+2PyO29h7iijIZx4plX0fheacJcAoYAASfgzgVIcXGYSq9GFyYocFLftQs8IOmmkgtOovs6d4oA==", + "license": "MIT", + "dependencies": { + "mdast-util-frontmatter": "^0.2.0", + "micromark-extension-frontmatter": "^0.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-1.0.0.tgz", + "integrity": "sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA==", + "license": "MIT", + "dependencies": { + "mdast-util-gfm": "^0.1.0", + "micromark-extension-gfm": "^0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", + "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6970,6 +9140,15 @@ "node": ">=4" } }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, "node_modules/rettime": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.10.1.tgz", @@ -7060,6 +9239,25 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -7081,6 +9279,48 @@ "license": "MIT", "optional": true }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "license": "MIT", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -7147,6 +9387,22 @@ "url": "https://opencollective.com/express" } }, + "node_modules/sentence-splitter": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/sentence-splitter/-/sentence-splitter-5.0.1.tgz", + "integrity": "sha512-Eu9l95hQfI0WdhXTznuBzqsFjTuL6UnPq341Ro1s2bjE3DMoBuhE0wk4z+rwbwVXfOAeuOQM0UF30HR2+66VuQ==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^13.4.1", + "structured-source": "^4.0.0" + } + }, + "node_modules/sentence-splitter/node_modules/@textlint/ast-node-types": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-13.4.1.tgz", + "integrity": "sha512-qrZyhCh8Ekk6nwArx3BROybm9BnX6vF7VcZbijetV/OM3yfS4rTYhoMWISmhVEP2H2re0CtWEyMl/XF+WdvVLQ==", + "license": "MIT" + }, "node_modules/serve-static": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", @@ -7173,6 +9429,52 @@ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -7278,7 +9580,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -7298,7 +9599,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -7315,7 +9615,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -7334,7 +9633,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -7417,6 +9715,15 @@ "simple-concat": "^1.0.0" } }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "license": "ISC", + "engines": { + "node": "*" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -7427,6 +9734,22 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -7451,6 +9774,19 @@ "dev": true, "license": "MIT" }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/strict-event-emitter": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", @@ -7468,19 +9804,75 @@ "safe-buffer": "~5.2.0" } }, - "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==", - "dev": true, + "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==", + "dev": true, + "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.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/strip-ansi": { @@ -7522,6 +9914,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.0.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7560,29 +9961,574 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "license": "MIT", - "optional": true, + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/textlint-rule-helper": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/textlint-rule-helper/-/textlint-rule-helper-2.5.0.tgz", + "integrity": "sha512-QIbFPtyqLy0g5BJn8mryk9iHzGYicNaFIpLFPiEnb4RXxrEGeQ2W2aARQ9yEXLIAqo+OwK4ndWBAWkbgJEPzTQ==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^15.2.1", + "structured-source": "^4.0.0", + "unist-util-visit": "^2.0.3" + } + }, + "node_modules/textlint-rule-ja-no-abusage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/textlint-rule-ja-no-abusage/-/textlint-rule-ja-no-abusage-3.0.0.tgz", + "integrity": "sha512-DIqPZgYTwTsvjX6Bgj7GA8vlwGMObagJpNoUtkucOaoy7E7GwUOL+knqFjcTtlkWSmoKpIkw5OWW5CV3kivlfQ==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0", + "morpheme-match-textlint": "^2.0.6", + "textlint-rule-prh": "^5.3.0" + } + }, + "node_modules/textlint-rule-ja-no-abusage/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/textlint-rule-ja-no-abusage/node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/textlint-rule-ja-no-abusage/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/textlint-rule-ja-no-abusage/node_modules/prh": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/prh/-/prh-5.4.4.tgz", + "integrity": "sha512-UATF+R/2H8owxwPvF12Knihu9aYGTuZttGHrEEq5NBWz38mREh23+WvCVKX3fhnIZIMV7ye6E1fnqAl+V6WYEw==", + "license": "MIT", + "dependencies": { + "commandpost": "^1.2.1", + "diff": "^4.0.1", + "js-yaml": "^3.9.1" + }, + "bin": { + "prh": "bin/prh" + } + }, + "node_modules/textlint-rule-ja-no-abusage/node_modules/textlint-rule-prh": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/textlint-rule-prh/-/textlint-rule-prh-5.3.0.tgz", + "integrity": "sha512-gdod+lL1SWUDyXs1ICEwvQawaSshT3mvPGufBIjF2R5WFPdKQDMsiuzsjkLm+aF+9d97dA6pFsiyC8gSW7mSgg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.7.5", + "prh": "^5.4.4", + "textlint-rule-helper": "^2.1.1", + "untildify": "^3.0.3" + } + }, + "node_modules/textlint-rule-ja-no-mixed-period": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/textlint-rule-ja-no-mixed-period/-/textlint-rule-ja-no-mixed-period-3.0.2.tgz", + "integrity": "sha512-/WHRvbAXPJxjDAmVYjIp5qBHPS7Uqv3H+fH0oGMWzujEV4n2URtXmxqTUv7nd4giTRqeV2yuMZWYRRgA9Mh0Sg==", + "license": "MIT", + "dependencies": { + "check-ends-with-period": "^3.0.2", + "textlint-rule-helper": "^2.2.4" + } + }, + "node_modules/textlint-rule-ja-no-redundant-expression": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/textlint-rule-ja-no-redundant-expression/-/textlint-rule-ja-no-redundant-expression-4.0.1.tgz", + "integrity": "sha512-r8Qe6S7u9N97wD0gcrASqBUdZs5CMEVlgc8Ul+D2NQFiOi1BoseOMo5I9yUsEZMAL46yh/eaw9+EWz6IDlPWeA==", + "license": "MIT", + "dependencies": { + "@textlint/regexp-string-matcher": "^1.1.0", + "kuromojin": "^3.0.0", + "morpheme-match": "^2.0.4", + "morpheme-match-all": "^2.0.5", + "textlint-rule-helper": "^2.2.1", + "textlint-util-to-string": "^3.1.1" + } + }, + "node_modules/textlint-rule-ja-no-successive-word": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/textlint-rule-ja-no-successive-word/-/textlint-rule-ja-no-successive-word-2.0.1.tgz", + "integrity": "sha512-XKTXkHwMu86SnGaj73B67U4apDdTquDKF3SfG24tRbzMyJoGe/Iba5VMId8sp8QHeTonp1bYOSxjZsbkpGyCNw==", + "license": "MIT", + "dependencies": { + "@textlint/regexp-string-matcher": "^1.1.0", + "kuromojin": "^3.0.0" + } + }, + "node_modules/textlint-rule-ja-no-weak-phrase": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/textlint-rule-ja-no-weak-phrase/-/textlint-rule-ja-no-weak-phrase-2.0.0.tgz", + "integrity": "sha512-jZ1/3VnE8Bz/p0CCe/+BVOmWE1cZwpDkjKb6hnq39nGk3OD4XPW7biYavK/4/mZhk4bh2+Vtu1xV26lg8d+vBw==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0", + "morpheme-match": "^2.0.4", + "morpheme-match-all": "^2.0.5" + } + }, + "node_modules/textlint-rule-ja-unnatural-alphabet": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/textlint-rule-ja-unnatural-alphabet/-/textlint-rule-ja-unnatural-alphabet-2.0.1.tgz", + "integrity": "sha512-n93V8qh6OKdh8OB6yLT+9Xl8DSoZ7gWi51tWdhlLEPIWgBm18nLMgm6Ck+nVc3eENOdRcQURWUpCGotI8wTemA==", + "license": "MIT", + "dependencies": { + "@textlint/regexp-string-matcher": "^1.0.2", + "match-index": "^1.0.1", + "regx": "^1.0.4" + } + }, + "node_modules/textlint-rule-max-comma": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/textlint-rule-max-comma/-/textlint-rule-max-comma-4.0.0.tgz", + "integrity": "sha512-2vKKXNg1YuTqr9/FrHvOGEHFe+6lNSDtzuEv+KRB+tuaj++UNa/YPvyY34UdDYuHUSKNcYdto8GlIUhAJDW9WQ==", + "license": "MIT", + "dependencies": { + "sentence-splitter": "^5.0.0", + "textlint-util-to-string": "^3.3.4" + } + }, + "node_modules/textlint-rule-max-kanji-continuous-len": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/textlint-rule-max-kanji-continuous-len/-/textlint-rule-max-kanji-continuous-len-1.1.1.tgz", + "integrity": "sha512-os+p7dS9Op4PtZV7B9/wnzN5qpDO2WR2kj7nTnqEPbApS06AXX+qf5eH3fKdm4blzUCcPF5ozMN8zbs3AJUAug==", + "license": "MIT", + "dependencies": { + "match-index": "^1.0.1", + "textlint-rule-helper": "^2.0.0" + } + }, + "node_modules/textlint-rule-max-ten": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/textlint-rule-max-ten/-/textlint-rule-max-ten-5.0.0.tgz", + "integrity": "sha512-EWOvbEa3Ukxz0+GAUEJ91DYFSC3IkyJ10dBcsU6VlL33k1BvTRoFr3m26w6upnXJffXQUI70Etn39I++2duyhA==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0", + "sentence-splitter": "^5.0.0", + "textlint-rule-helper": "^2.3.1", + "textlint-util-to-string": "^3.3.4" + } + }, + "node_modules/textlint-rule-no-double-negative-ja": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/textlint-rule-no-double-negative-ja/-/textlint-rule-no-double-negative-ja-2.0.1.tgz", + "integrity": "sha512-LRofmNt+nd2mp+AHmG0ltk9AlbzKbWPE+EToYQ1zORCd8N8suE1YxNEplz9OeQ59ea9ITtudDIWoqeHaZnbDsg==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0" + } + }, + "node_modules/textlint-rule-no-doubled-conjunction": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/textlint-rule-no-doubled-conjunction/-/textlint-rule-no-doubled-conjunction-3.0.1.tgz", + "integrity": "sha512-fRJEiy0rkrmUDVdgzGiUKAgGngziUfsjL4eqY4a3YfFxXwtczOP+hyHfvLNrHOUI58Y6lNoLZpa5lNNXbzFyNg==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0", + "sentence-splitter": "^5.0.0", + "textlint-rule-helper": "^2.3.1" + } + }, + "node_modules/textlint-rule-no-doubled-conjunctive-particle-ga": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/textlint-rule-no-doubled-conjunctive-particle-ga/-/textlint-rule-no-doubled-conjunctive-particle-ga-3.0.0.tgz", + "integrity": "sha512-4IowX2YlTlD9VifThZwpENRh918BpPNTks0i4bOL7Gn82jUiXK0EZuV8Jtksm7i+RYG1xsO0U7P9AnxmuSxeDg==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0", + "sentence-splitter": "^5.0.0", + "textlint-rule-helper": "^2.3.1", + "textlint-util-to-string": "^3.3.4" + } + }, + "node_modules/textlint-rule-no-doubled-joshi": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/textlint-rule-no-doubled-joshi/-/textlint-rule-no-doubled-joshi-5.1.1.tgz", + "integrity": "sha512-bxiuqZiHE9ZZGHDX+O6J4vzhre7ghb7NBkPi/5TAWVvnQLULgY3COx/KXJgFItPmSrpYF8/AT/uTHC4QOg59qw==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0", + "sentence-splitter": "^5.0.0", + "textlint-rule-helper": "^2.3.1", + "textlint-util-to-string": "^3.3.4" + } + }, + "node_modules/textlint-rule-no-dropping-the-ra": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/textlint-rule-no-dropping-the-ra/-/textlint-rule-no-dropping-the-ra-3.0.0.tgz", + "integrity": "sha512-KbSIlcxj1kLs4sGSMSLGA8OmgRoaPAWtodJaGEyEUiy7uiZM/VPqYALpuD8vf16N1OR5SM/bXXeZFME65r8ZgQ==", + "license": "MIT", + "dependencies": { + "kuromojin": "^3.0.0", + "textlint-rule-helper": "^2.1.1" + } + }, + "node_modules/textlint-rule-no-exclamation-question-mark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/textlint-rule-no-exclamation-question-mark/-/textlint-rule-no-exclamation-question-mark-1.1.0.tgz", + "integrity": "sha512-FcBH3uH2qp5VG7I9LKwolUCcPigONcsdam1JhAFPcu10YZNYX0r1l2y9Hzg+E4+1fXLgtGyiObWwfsfelTx8Bw==", + "license": "MIT", + "dependencies": { + "@textlint/regexp-string-matcher": "^1.1.0", + "match-index": "^1.0.3", + "textlint-rule-helper": "^2.1.1" + } + }, + "node_modules/textlint-rule-no-hankaku-kana": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/textlint-rule-no-hankaku-kana/-/textlint-rule-no-hankaku-kana-2.0.1.tgz", + "integrity": "sha512-39s94HK6V1xnII1haYiYQnWy1YQAKK7Zj0mcpUMFHHC4M5JdsRnhGs6DQPVEff0gQIFV0iuDNlofXt15kjMtEA==", + "license": "MIT", + "dependencies": { + "textlint-rule-helper": "^2.3.0", + "textlint-tester": "^13.3.1" + } + }, + "node_modules/textlint-rule-no-mix-dearu-desumasu": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/textlint-rule-no-mix-dearu-desumasu/-/textlint-rule-no-mix-dearu-desumasu-6.0.4.tgz", + "integrity": "sha512-SmALtOFbtmJ//k2iLMvtqhGrgJ/6uDVZFK7TBj2npVAbt10VxgLL87K+62pQ/BqiN9DpOVObshVFdug7lUOKHw==", + "license": "MIT", + "dependencies": { + "analyze-desumasu-dearu": "^5.0.2", + "textlint-rule-helper": "^2.3.1" + } + }, + "node_modules/textlint-rule-no-nfd": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/textlint-rule-no-nfd/-/textlint-rule-no-nfd-2.0.2.tgz", + "integrity": "sha512-lIUvcQ+wqtConpPQU2YwEJl2dRcRyyrxPYZ3V76UwnkVg++XPLIrE5mLDgyNE/UIQ34e/KitJfMLqKWvnkFbNQ==", + "license": "MIT", + "dependencies": { + "match-index": "^1.0.3", + "textlint-rule-helper": "^2.3.0" + } + }, + "node_modules/textlint-rule-no-zero-width-spaces": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/textlint-rule-no-zero-width-spaces/-/textlint-rule-no-zero-width-spaces-1.0.1.tgz", + "integrity": "sha512-AkxpzBILGB4YsXddzHx2xqpXmqMv5Yd+PQm4anUV+ADSJuwLP1Jd6yHf/LOtu9j3ps8K3XM9vQrXRK73z0bU3A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/hata6502" + } + }, + "node_modules/textlint-rule-preset-ja-technical-writing": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/textlint-rule-preset-ja-technical-writing/-/textlint-rule-preset-ja-technical-writing-12.0.2.tgz", + "integrity": "sha512-BBVY6oA5V799k5wRfP+gCpDHsp6vWjWX2UT+/KLlAFFsNdmRB8Z6qyOnqiOjfzmLGIRgoMcPI1dXj5upOqnD6Q==", + "license": "MIT", + "dependencies": { + "@textlint-rule/textlint-rule-no-invalid-control-character": "^3.0.0", + "@textlint-rule/textlint-rule-no-unmatched-pair": "^2.0.4", + "@textlint/module-interop": "^14.4.0", + "textlint-rule-ja-no-abusage": "^3.0.0", + "textlint-rule-ja-no-mixed-period": "^3.0.1", + "textlint-rule-ja-no-redundant-expression": "^4.0.1", + "textlint-rule-ja-no-successive-word": "^2.0.1", + "textlint-rule-ja-no-weak-phrase": "^2.0.0", + "textlint-rule-ja-unnatural-alphabet": "2.0.1", + "textlint-rule-max-comma": "^4.0.0", + "textlint-rule-max-kanji-continuous-len": "^1.1.1", + "textlint-rule-max-ten": "^5.0.0", + "textlint-rule-no-double-negative-ja": "^2.0.1", + "textlint-rule-no-doubled-conjunction": "^3.0.0", + "textlint-rule-no-doubled-conjunctive-particle-ga": "^3.0.0", + "textlint-rule-no-doubled-joshi": "^5.1.0", + "textlint-rule-no-dropping-the-ra": "^3.0.0", + "textlint-rule-no-exclamation-question-mark": "^1.1.0", + "textlint-rule-no-hankaku-kana": "^2.0.1", + "textlint-rule-no-mix-dearu-desumasu": "^6.0.3", + "textlint-rule-no-nfd": "^2.0.2", + "textlint-rule-no-zero-width-spaces": "^1.0.1", + "textlint-rule-preset-jtf-style": "^3.0.1", + "textlint-rule-sentence-length": "^5.2.0" + } + }, + "node_modules/textlint-rule-preset-jtf-style": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/textlint-rule-preset-jtf-style/-/textlint-rule-preset-jtf-style-3.0.3.tgz", + "integrity": "sha512-NTvqjg3oMTGjSDoH6MnYu+DDWW6cEghA66Lb8N0bheTphAj99aaG10HGhwTfDbaH2P6NfPQvRP5ISxiXCT9zdg==", + "license": "MIT", + "dependencies": { + "analyze-desumasu-dearu": "^2.1.2", + "japanese-numerals-to-number": "^1.0.2", + "match-index": "^1.0.3", + "moji": "^0.5.1", + "regexp.prototype.flags": "^1.5.3", + "regx": "^1.0.4", + "textlint-rule-helper": "^2.3.1", + "textlint-rule-prh": "^6.0.0" + } + }, + "node_modules/textlint-rule-preset-jtf-style/node_modules/analyze-desumasu-dearu": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/analyze-desumasu-dearu/-/analyze-desumasu-dearu-2.1.5.tgz", + "integrity": "sha512-4YPL7IRAuaZflE10+BVhKr6k5KQl/DiLeNCIF7ISqKr0ogM2hqm9ztRNCPqL/xYDI7hfuIHR8T+U7mIDRLQNXw==", + "license": "MIT" + }, + "node_modules/textlint-rule-prh": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/textlint-rule-prh/-/textlint-rule-prh-6.1.0.tgz", + "integrity": "sha512-KrchADHw1/LZ/tAQ2XwL/XdUhunKCvlNmwgp+6hdyzuWX7uojOkDdJWWV0KAN4XWsK6Te5w/SZcYwQ7X6i3B0A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.0", + "prh": "^5.4.4", + "textlint-rule-helper": "^2.3.1" + } + }, + "node_modules/textlint-rule-prh/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/textlint-rule-prh/node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/textlint-rule-prh/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/textlint-rule-prh/node_modules/prh": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/prh/-/prh-5.4.4.tgz", + "integrity": "sha512-UATF+R/2H8owxwPvF12Knihu9aYGTuZttGHrEEq5NBWz38mREh23+WvCVKX3fhnIZIMV7ye6E1fnqAl+V6WYEw==", + "license": "MIT", + "dependencies": { + "commandpost": "^1.2.1", + "diff": "^4.0.1", + "js-yaml": "^3.9.1" + }, + "bin": { + "prh": "bin/prh" + } + }, + "node_modules/textlint-rule-sentence-length": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/textlint-rule-sentence-length/-/textlint-rule-sentence-length-5.2.1.tgz", + "integrity": "sha512-z4HylabPy+e1I5DcuzDmcT65hvyytTlsD+uM49JkCBTSJBWqzQQ3kCGk4b1cF+kANS2HifWNnpTG/jfSOeavIw==", + "license": "MIT", + "dependencies": { + "@textlint/regexp-string-matcher": "^2.0.2", + "sentence-splitter": "^5.0.0", + "textlint-rule-helper": "^2.3.1", + "textlint-util-to-string": "^3.3.4" + } + }, + "node_modules/textlint-rule-sentence-length/node_modules/@textlint/regexp-string-matcher": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@textlint/regexp-string-matcher/-/regexp-string-matcher-2.0.2.tgz", + "integrity": "sha512-OXLD9XRxMhd3S0LWuPHpiARQOI7z9tCOs0FsynccW2lmyZzHHFJ9/eR6kuK9xF459Qf+740qI5h+/0cx+NljzA==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^4.0.0", + "lodash.sortby": "^4.7.0", + "lodash.uniq": "^4.5.0", + "lodash.uniqwith": "^4.5.0" + } + }, + "node_modules/textlint-tester": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/textlint-tester/-/textlint-tester-13.4.1.tgz", + "integrity": "sha512-Ubm9kUZ/NyY0Ggo1RkW2o5QSx6EJ/ogMT1kD5b5pk4cdFTWpUSs8StDMROgcz29wPhvS6sY/35qYALzqyZh8ew==", + "license": "MIT", + "dependencies": { + "@textlint/feature-flag": "^13.4.1", + "@textlint/kernel": "^13.4.1", + "@textlint/textlint-plugin-markdown": "^13.4.1", + "@textlint/textlint-plugin-text": "^13.4.1" + } + }, + "node_modules/textlint-tester/node_modules/@textlint/ast-node-types": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-13.4.1.tgz", + "integrity": "sha512-qrZyhCh8Ekk6nwArx3BROybm9BnX6vF7VcZbijetV/OM3yfS4rTYhoMWISmhVEP2H2re0CtWEyMl/XF+WdvVLQ==", + "license": "MIT" + }, + "node_modules/textlint-tester/node_modules/@textlint/ast-tester": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-tester/-/ast-tester-13.4.1.tgz", + "integrity": "sha512-YSHUR1qDgMPGF5+nvrquEhif6zRJ667xUnfP/9rTNtThIhoTQINvczr5/7xa43F1PDWplL6Curw+2jrE1qHwGQ==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^13.4.1", + "debug": "^4.3.4" + } + }, + "node_modules/textlint-tester/node_modules/@textlint/ast-traverse": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-traverse/-/ast-traverse-13.4.1.tgz", + "integrity": "sha512-uucuC7+NHWkXx2TX5vuyreuHeb+GFiA83V65I+FnYP5EC4dAMOQ86rTSPrZmCwLz+qIWgfDgihGzPccpj3EZGg==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^13.4.1" + } + }, + "node_modules/textlint-tester/node_modules/@textlint/feature-flag": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/feature-flag/-/feature-flag-13.4.1.tgz", + "integrity": "sha512-qY8gKUf30XtzWMTkwYeKytCo6KPx6milpz8YZhuRsEPjT/5iNdakJp5USWDQWDrwbQf7RbRncQdU+LX5JbM9YA==", + "license": "MIT" + }, + "node_modules/textlint-tester/node_modules/@textlint/kernel": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/kernel/-/kernel-13.4.1.tgz", + "integrity": "sha512-r2sUhjPysFjl2Ax37x9AfWkJM8jgKN0bL4SX3xRzOukdcj69Dst5On5qBZtULaVMX1LDkwkdxA6ZEADmq27qQA==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^13.4.1", + "@textlint/ast-tester": "^13.4.1", + "@textlint/ast-traverse": "^13.4.1", + "@textlint/feature-flag": "^13.4.1", + "@textlint/source-code-fixer": "^13.4.1", + "@textlint/types": "^13.4.1", + "@textlint/utils": "^13.4.1", + "debug": "^4.3.4", + "fast-equals": "^4.0.3", + "structured-source": "^4.0.0" + } + }, + "node_modules/textlint-tester/node_modules/@textlint/source-code-fixer": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/source-code-fixer/-/source-code-fixer-13.4.1.tgz", + "integrity": "sha512-Sl29f3Tpimp0uVE3ysyJBjxaFTVYLOXiJX14eWCQ/kC5ZhIXGosEbStzkP1n8Urso1rs1W4p/2UemVAm3NH2ng==", + "license": "MIT", + "dependencies": { + "@textlint/types": "^13.4.1", + "debug": "^4.3.4" + } + }, + "node_modules/textlint-tester/node_modules/@textlint/text-to-ast": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/text-to-ast/-/text-to-ast-13.4.1.tgz", + "integrity": "sha512-vCA7uMmbjRv06sEHPbwxTV5iS8OQedC5s7qwmXnWAn2LLWxg4Yp98mONPS1o4D5cPomzYyKNCSfbLwu6yJBUQA==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^13.4.1" + } + }, + "node_modules/textlint-tester/node_modules/@textlint/textlint-plugin-text": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-text/-/textlint-plugin-text-13.4.1.tgz", + "integrity": "sha512-z0p5B8WUfTCIRmhjVHFfJv719oIElDDKWOIZei4CyYkfMGo0kq8fkrYBkUR6VZ6gofHwc+mwmIABdUf1rDHzYA==", + "license": "MIT", + "dependencies": { + "@textlint/text-to-ast": "^13.4.1" + } + }, + "node_modules/textlint-tester/node_modules/@textlint/types": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-13.4.1.tgz", + "integrity": "sha512-1ApwQa31sFmiJeJ5yTNFqjbb2D1ICZvIDW0tFSM0OtmQCSDFNcKD3YrrwDBgSokZ6gWQq/FpNjlhi6iETUWt0Q==", + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^13.4.1" + } + }, + "node_modules/textlint-tester/node_modules/@textlint/utils": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/utils/-/utils-13.4.1.tgz", + "integrity": "sha512-wX8RT1ejHAPTDmqlzngf0zI5kYoe3QvGDcj+skoTxSv+m/wOs/NyEr92d+ahCP32YqFYzXlqU7aDx2FkULKT+g==", + "license": "MIT" + }, + "node_modules/textlint-util-to-string": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/textlint-util-to-string/-/textlint-util-to-string-3.3.4.tgz", + "integrity": "sha512-XF4Qfw0ES+czKy03BwuvBUoXC8NAg920VuRxW0pd72fW76zMeMbPI/bRN5PHq3SbCdOm7U69/Pk+DX34xqIYqA==", + "license": "MIT", "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" + "@textlint/ast-node-types": "^13.4.1", + "rehype-parse": "^6.0.1", + "structured-source": "^4.0.0", + "unified": "^8.4.0" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/textlint-util-to-string/node_modules/@textlint/ast-node-types": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-13.4.1.tgz", + "integrity": "sha512-qrZyhCh8Ekk6nwArx3BROybm9BnX6vF7VcZbijetV/OM3yfS4rTYhoMWISmhVEP2H2re0CtWEyMl/XF+WdvVLQ==", + "license": "MIT" + }, + "node_modules/textlint-util-to-string/node_modules/unified": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-8.4.2.tgz", + "integrity": "sha512-JCrmN13jI4+h9UAyKEoGcDZV+i1E7BLFuG7OsaDvTXI5P0qhHX+vZO/kOhz9jn8HGENDKbwSeB0nVOg4gVStGA==", "license": "MIT", - "optional": true, "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" }, - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/tiny-invariant": { @@ -7655,6 +10601,21 @@ "dev": true, "license": "MIT" }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "license": "MIT", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7704,6 +10665,23 @@ "node": ">=20" } }, + "node_modules/traverse": { + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.11.tgz", + "integrity": "sha512-vxXDZg8/+p3gblxB6BhhG5yWVn1kGRlaL8O78UDXc3wRnPizB5g83dcvWV1jpDMIPnjZjOFuxlMmE82XJ4407w==", + "license": "MIT", + "dependencies": { + "gopd": "^1.2.0", + "typedarray.prototype.slice": "^1.0.5", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -7714,6 +10692,16 @@ "tree-kill": "cli.js" } }, + "node_modules/trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", @@ -7791,6 +10779,102 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray.prototype.slice": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz", + "integrity": "sha512-q7QNVDGTdl702bVFiI5eY4l/HkgCM6at9KhcFbgUAzezHFbOVy4+0O/lCjsABEQwbZPravVfBIiBVGo89yzHFg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "math-intrinsics": "^1.1.0", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-offset": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -7829,6 +10913,24 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.8.tgz", @@ -7856,6 +10958,76 @@ "pathe": "^2.0.3" } }, + "node_modules/unified": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", + "license": "MIT", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -7876,6 +11048,15 @@ "url": "https://github.com/sponsors/kettanaito" } }, + "node_modules/untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -7933,6 +11114,20 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7950,6 +11145,36 @@ "node": ">= 0.8" } }, + "node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/victory-vendor": { "version": "37.3.6", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", @@ -8151,6 +11376,16 @@ "loose-envify": "^1.0.0" } }, + "node_modules/web-namespaces": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", + "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/webidl-conversions": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", @@ -8202,6 +11437,91 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.21.tgz", + "integrity": "sha512-zbRA8cVm6io/d5W8uIe2hblzN76/Wm3v/yiythQvr+dpBWeqhPSWIDNj4zOyHi4zKbMK6DN34Xsr9jPHJERAEw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -8791,6 +12111,17 @@ "devOptional": true, "license": "ISC" }, + "node_modules/write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha512-SdrHoC/yVBPpV0Xq/mUZQIpW2sWXAShb/V4pomcJXh92RuaO+f3UTWItiR3Px+pLnV2PvC2/bfn5cwr5X6Vfxw==", + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", @@ -8830,6 +12161,15 @@ "dev": true, "license": "MIT" }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -8934,6 +12274,15 @@ "error-stack-parser-es": "^1.0.5" } }, + "node_modules/zlibjs": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz", + "integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/zod": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", @@ -8956,6 +12305,16 @@ "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } + }, + "node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/frontend/package.json b/frontend/package.json index 1eb1842e..2c82e4d0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,15 +21,20 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.11.2", + "@textlint/kernel": "^15.7.1", + "@textlint/textlint-plugin-text": "^15.7.1", "dompurify": "^3.4.7", "marked": "^17.0.4", + "prh": "^6.0.6", "react": "^18.3.1", "react-dom": "^18.3.1", "react-pdf": "^9.2.1", "react-redux": "^9.2.0", "react-router-dom": "^7.13.1", "recharts": "^3.8.0", - "redux-persist": "^6.0.0" + "redux-persist": "^6.0.0", + "textlint-rule-preset-ja-technical-writing": "^12.0.2", + "textlint-rule-prh": "^6.1.0" }, "devDependencies": { "@eslint/js": "^9.39.4", @@ -37,11 +42,13 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@textlint/types": "^15.7.1", "@types/node": "^25.5.2", "@types/react": "^18.3.15", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react": "^4.4.1", "@vitest/coverage-v8": "^4.1.2", + "assert": "^2.1.0", "concurrently": "^9.2.1", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", @@ -52,6 +59,8 @@ "jsdom": "^29.0.1", "msw": "^2.13.2", "openapi-typescript": "^7.13.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", "playwright": "^1.56.0", "prettier": "^3.8.1", "typescript": "^5.7.2", diff --git a/frontend/public/_headers b/frontend/public/_headers new file mode 100644 index 00000000..dad4c164 --- /dev/null +++ b/frontend/public/_headers @@ -0,0 +1,7 @@ +# kuromoji(校正機能の形態素解析)辞書の配信ヘッダ(Cloudflare Pages 用)。 +# .gz を gzip 転送エンコーディング扱いさせず、生の gzip バイト列として返す +# (kuromoji が自前で gunzip するため)。octet-stream 指定で edge の自動圧縮も避ける。 +# 辞書は不変なので長期キャッシュする。 +/kuromoji-dict/* + Content-Type: application/octet-stream + Cache-Control: public, max-age=31536000, immutable diff --git a/frontend/public/kuromoji-dict/base.dat.gz b/frontend/public/kuromoji-dict/base.dat.gz new file mode 100644 index 00000000..917954c3 Binary files /dev/null and b/frontend/public/kuromoji-dict/base.dat.gz differ diff --git a/frontend/public/kuromoji-dict/cc.dat.gz b/frontend/public/kuromoji-dict/cc.dat.gz new file mode 100644 index 00000000..7d867067 Binary files /dev/null and b/frontend/public/kuromoji-dict/cc.dat.gz differ diff --git a/frontend/public/kuromoji-dict/check.dat.gz b/frontend/public/kuromoji-dict/check.dat.gz new file mode 100644 index 00000000..7e977a10 Binary files /dev/null and b/frontend/public/kuromoji-dict/check.dat.gz differ diff --git a/frontend/public/kuromoji-dict/tid.dat.gz b/frontend/public/kuromoji-dict/tid.dat.gz new file mode 100644 index 00000000..195a8707 Binary files /dev/null and b/frontend/public/kuromoji-dict/tid.dat.gz differ diff --git a/frontend/public/kuromoji-dict/tid_map.dat.gz b/frontend/public/kuromoji-dict/tid_map.dat.gz new file mode 100644 index 00000000..d04bba3b Binary files /dev/null and b/frontend/public/kuromoji-dict/tid_map.dat.gz differ diff --git a/frontend/public/kuromoji-dict/tid_pos.dat.gz b/frontend/public/kuromoji-dict/tid_pos.dat.gz new file mode 100644 index 00000000..e4d5cffd Binary files /dev/null and b/frontend/public/kuromoji-dict/tid_pos.dat.gz differ diff --git a/frontend/public/kuromoji-dict/unk.dat.gz b/frontend/public/kuromoji-dict/unk.dat.gz new file mode 100644 index 00000000..83464686 Binary files /dev/null and b/frontend/public/kuromoji-dict/unk.dat.gz differ diff --git a/frontend/public/kuromoji-dict/unk_char.dat.gz b/frontend/public/kuromoji-dict/unk_char.dat.gz new file mode 100644 index 00000000..8b7693a3 Binary files /dev/null and b/frontend/public/kuromoji-dict/unk_char.dat.gz differ diff --git a/frontend/public/kuromoji-dict/unk_compat.dat.gz b/frontend/public/kuromoji-dict/unk_compat.dat.gz new file mode 100644 index 00000000..87030e97 Binary files /dev/null and b/frontend/public/kuromoji-dict/unk_compat.dat.gz differ diff --git a/frontend/public/kuromoji-dict/unk_invoke.dat.gz b/frontend/public/kuromoji-dict/unk_invoke.dat.gz new file mode 100644 index 00000000..c6736eba Binary files /dev/null and b/frontend/public/kuromoji-dict/unk_invoke.dat.gz differ diff --git a/frontend/public/kuromoji-dict/unk_map.dat.gz b/frontend/public/kuromoji-dict/unk_map.dat.gz new file mode 100644 index 00000000..12d427bf Binary files /dev/null and b/frontend/public/kuromoji-dict/unk_map.dat.gz differ diff --git a/frontend/public/kuromoji-dict/unk_pos.dat.gz b/frontend/public/kuromoji-dict/unk_pos.dat.gz new file mode 100644 index 00000000..50bb65de Binary files /dev/null and b/frontend/public/kuromoji-dict/unk_pos.dat.gz differ diff --git a/frontend/src/components/forms/CareerDiffModal.module.css b/frontend/src/components/forms/CareerDiffModal.module.css index 3befaf3a..b5e32263 100644 --- a/frontend/src/components/forms/CareerDiffModal.module.css +++ b/frontend/src/components/forms/CareerDiffModal.module.css @@ -106,6 +106,10 @@ .sidebarHead { flex-shrink: 0; + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 0.5rem; padding: 0.4rem 0.7rem; font-size: 0.8rem; font-weight: 700; @@ -120,37 +124,45 @@ overflow-y: auto; display: flex; flex-direction: column; - gap: 0.4rem; + gap: 0.5rem; + flex: 1 1 auto; + min-height: 0; } -.row { +/* 1 フィールド分のレビュー項目(差分+校正をまとめたカード)。 */ +.entry { display: flex; - align-items: stretch; - gap: 0.4rem; + flex-direction: column; border: 1px solid var(--border-color, #e0e0e0); border-radius: 6px; overflow: hidden; } -/* 行本体はクリックでスクロールするボタン。装飾はテキストブロック風に戻す。 */ -.rowMain { - flex: 1; - min-width: 0; +/* 見出し(クリックで右ペインの該当箇所へスクロール)。 */ +.entryHead { text-align: left; - background: transparent; + background: var(--bg-page, #f7f7f8); color: inherit; border: none; - border-radius: 0; - padding: 0.45rem 0.55rem; - font-weight: 400; + border-bottom: 1px solid var(--border-color, #ececec); + padding: 0.35rem 0.55rem; cursor: pointer; } -.rowHead { +/* 差分行: バッジ+旧→新 と 元に戻すボタン。 */ +.entryDiff { display: flex; align-items: center; gap: 0.4rem; - margin-bottom: 0.2rem; + padding: 0.35rem 0.5rem 0.35rem 0.55rem; +} + +.diffMain { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 0.2rem; } .badge { @@ -177,7 +189,7 @@ .label { font-size: 0.78rem; font-weight: 600; - word-break: break-word; + overflow-wrap: break-word; } .values { @@ -191,7 +203,7 @@ .oldValue { color: var(--text-muted, #888); text-decoration: line-through; - word-break: break-word; + overflow-wrap: break-word; } .arrow { @@ -201,14 +213,13 @@ .newValue { color: var(--text-primary, #111); font-weight: 500; - word-break: break-word; + overflow-wrap: break-word; } /* VSCode の diff の revert 矢印風。各変更行を編集前(保存済み)へ戻すアイコンボタン。 */ .rollback { flex-shrink: 0; align-self: center; - margin-right: 0.4rem; width: 26px; height: 26px; padding: 0; @@ -243,3 +254,58 @@ padding: 0.75rem 1.25rem; border-top: 1px solid var(--border-color, #e0e0e0); } + +.proofreadLoading { + font-size: 0.7rem; + font-weight: 400; + color: #3b82f6; +} + +/* 校正の指摘リスト(青系・控えめ)。エントリ内の差分の下に続く。 */ +.entryIssues { + list-style: none; + margin: 0; + padding: 0.3rem 0.5rem 0.4rem 0.55rem; + display: flex; + flex-direction: column; + gap: 0.3rem; + background: rgba(37, 99, 235, 0.05); + border-top: 1px solid rgba(37, 99, 235, 0.18); +} + +.proofreadItem { + border-left: 2px solid rgba(37, 99, 235, 0.45); + padding-left: 0.45rem; +} + +.proofreadMessage { + margin: 0; + font-size: 0.74rem; + color: var(--text-primary, #1f2937); + line-height: 1.4; + white-space: pre-wrap; + overflow-wrap: break-word; +} + +.proofreadExcerpt { + margin: 0.15rem 0 0; + font-size: 0.68rem; + color: var(--text-muted, #6b7280); + overflow-wrap: break-word; +} + +.proofreadEmpty { + margin: 0; + padding: 0 0.7rem 0.4rem; + font-size: 0.74rem; + color: var(--text-muted, #6b7280); +} + +.proofreadHint { + flex-shrink: 0; + margin: 0; + padding: 0.35rem 0.7rem 0.5rem; + font-size: 0.66rem; + color: #2563eb; + line-height: 1.4; +} diff --git a/frontend/src/components/forms/CareerDiffModal.tsx b/frontend/src/components/forms/CareerDiffModal.tsx index bf55d039..dae5b985 100644 --- a/frontend/src/components/forms/CareerDiffModal.tsx +++ b/frontend/src/components/forms/CareerDiffModal.tsx @@ -1,6 +1,8 @@ import { useMemo, useRef } from "react"; -import { DIFF_DIALOG_MESSAGES as D } from "../../constants/messages"; +import { DIFF_DIALOG_MESSAGES as D, PROOFREAD_MESSAGES as P } from "../../constants/messages"; +import type { ProofreadIssue } from "../../proofread/types"; +import { buildReviewEntries } from "../../utils/careerReview"; import type { CareerChange, ChangeKind } from "../../utils/careerDiff"; import { annotateHtml, @@ -20,6 +22,7 @@ const KIND_LABEL: Record = { /** * iframe 内に注入する diff 着色 CSS。backend の resume.css に追記する形で srcDoc に埋め込む。 * 緑=追加 / 赤=削除 / 黄=修正。VSCode 系 diff の配色に寄せる。 + * 校正指摘は青の波線(diff の背景色と重ねても潰れないよう下線で表現)。 */ const DIFF_CSS = ` body { margin: 0; padding: 12px 16px; background: #fff; } @@ -27,6 +30,11 @@ const DIFF_CSS = ` .diff-added { background: rgba(22,163,74,0.18); box-shadow: 0 0 0 1px rgba(22,163,74,0.45); } .diff-removed { background: rgba(220,38,38,0.16); box-shadow: 0 0 0 1px rgba(220,38,38,0.40); } .diff-modified { background: rgba(234,179,8,0.25); box-shadow: 0 0 0 1px rgba(234,179,8,0.50); } + .diff-proofread { + text-decoration: underline wavy #2563eb; + text-decoration-skip-ink: none; + text-underline-offset: 2px; + } details.fold { margin: 3px 0; } summary.fold-summary { cursor: pointer; list-style: none; font-size: 8pt; color: #6b7280; @@ -63,6 +71,9 @@ export function CareerDiffModal({ loading, error, saving, + issues, + proofreading, + proofreadError, onConfirm, onCancel, onRollback, @@ -74,6 +85,12 @@ export function CareerDiffModal({ loading: boolean; error: string | null; saving: boolean; + /** 編集中フォームの校正指摘(フィールド横断)。 */ + issues: ProofreadIssue[]; + /** 校正処理中フラグ。 */ + proofreading: boolean; + /** 校正失敗時のメッセージ(null なら正常)。 */ + proofreadError: string | null; onConfirm: () => void; onCancel: () => void; onRollback: (change: CareerChange) => void; @@ -83,7 +100,20 @@ export function CareerDiffModal({ const pathKindMap = useMemo(() => buildPathKindMap(changes), [changes]); + /** + * 変更点と校正指摘を 1 本のレビュー一覧へ統合し、PDF レイアウト順に並べる。 + * 左右ペイン(PDF)とサイドバーの縦順が一致し、上から順に突合できる。 + */ + const reviewEntries = useMemo(() => buildReviewEntries(changes, issues), [changes, issues]); + + /** 校正指摘のあるフィールド id 集合(編集中ペインの青マーク/折りたたみ除外に使う)。 */ + const proofreadFieldIds = useMemo( + () => new Set(issues.map((issue) => issue.fieldId)), + [issues], + ); + // 着色(annotateHtml)→ 変更なし領域を畳む(foldUnchanged)の順で整形する。 + // baseline(保存済み)側は校正マークを付けない(指摘は編集中フォームに対するもの)。 const baselineDoc = useMemo(() => { if (baselineHtml === null) return null; return buildSrcDoc(css, foldUnchanged(annotateHtml(baselineHtml, pathKindMap), pathKindMap)); @@ -91,17 +121,17 @@ export function CareerDiffModal({ const editedDoc = useMemo(() => { if (editedHtml === null) return null; - // 着色 → 削除跡のプレースホルダ挿入 → 変更なし領域の折りたたみ、の順で整形する。 - const annotated = annotateHtml(editedHtml, pathKindMap); + // 着色(差分+校正青マーク)→ 削除跡のプレースホルダ挿入 → 変更なし領域の折りたたみ。 + // 校正指摘のある項目は畳まないよう foldUnchanged にも fieldId 集合を渡す。 + const annotated = annotateHtml(editedHtml, pathKindMap, proofreadFieldIds); const withStubs = injectRemovedPlaceholders(annotated, changes); - return buildSrcDoc(css, foldUnchanged(withStubs, pathKindMap)); - }, [editedHtml, css, pathKindMap, changes]); + return buildSrcDoc(css, foldUnchanged(withStubs, pathKindMap, proofreadFieldIds)); + }, [editedHtml, css, pathKindMap, changes, proofreadFieldIds]); - /** 変更点行クリックで、右ペイン(編集中)の該当ノードへスクロールする。 */ - const scrollToChange = (change: CareerChange) => { + /** レビュー項目クリックで、右ペイン(編集中)の該当ノードへスクロールする。 */ + const scrollToPath = (fp: string) => { const doc = editedFrameRef.current?.contentDocument; if (!doc) return; - const fp = change.path.join("."); const escaped = CSS.escape(fp); const target = doc.querySelector(`[data-fp="${escaped}"]`) ?? @@ -164,50 +194,82 @@ export function CareerDiffModal({ {loading && editedDoc &&
{D.PREVIEW_LOADING}
} - {/* 変更点サイドバー */} + {/* レビュー一覧: 変更点と校正を 1 本に統合し PDF レイアウト順に並べる。 */} diff --git a/frontend/src/components/forms/CareerResumeForm.tsx b/frontend/src/components/forms/CareerResumeForm.tsx index c0176e12..1adc664a 100644 --- a/frontend/src/components/forms/CareerResumeForm.tsx +++ b/frontend/src/components/forms/CareerResumeForm.tsx @@ -14,6 +14,7 @@ import { SUCCESS_MESSAGES, UI_MESSAGES } from "../../constants/messages"; import { createInitialCareerForm, mapCareerResumeToForm } from "../../formMappers"; import { useCareerDirty } from "../../hooks/career/useCareerDirty"; import { useImportPanelLayout } from "../../hooks/career/useImportPanelLayout"; +import { useProofread } from "../../hooks/career/useProofread"; import { useResumeDiffPreview } from "../../hooks/career/useResumeDiffPreview"; import { useResumeImportAssist } from "../../hooks/career/useResumeImportAssist"; import { useDocumentForm } from "../../hooks/useDocumentForm"; @@ -86,16 +87,23 @@ export function CareerResumeForm() { /** * baseline(保存済み)と form(編集中)の変更点リスト。左右 diff モーダルのサイドバーと - * ハイライト突合に使う。baseline が未ロード(null)のときは form 同士を比較して変更なし扱い。 + * ハイライト突合に使う。 + * + * baseline が未ロード(null = 新規作成の初回保存)のときは「空フォーム」を基準にする。 + * これにより初回保存でも全項目が「追加」として変更点に立ち、確認ダイアログが開く + * (= 初回も校正を見せる)。既存データで差分が無い場合は changes が空のまま直接保存される。 */ const changes = useMemo( - () => buildCareerChanges(form, baseline ?? form), + () => buildCareerChanges(form, baseline ?? createInitialCareerForm()), [form, baseline], ); /** 左右 diff モーダル用の整形 HTML プレビュー(保存済み / 編集中)。開いている間だけ取得する。 */ const preview = useResumeDiffPreview(form, baseline, showSaveConfirm); + /** 保存確認ダイアログが開いている間、編集中フォームを校正する(誤字脱字・表記ゆれ)。 */ + const proofread = useProofread(form, showSaveConfirm); + const { downloading, previewUrl, @@ -207,6 +215,9 @@ export function CareerResumeForm() { loading={preview.loading} error={preview.error} saving={saving} + issues={proofread.issues} + proofreading={proofread.proofreading} + proofreadError={proofread.error} onConfirm={handleConfirmSave} onCancel={() => setShowSaveConfirm(false)} onRollback={(change) => setForm((prev) => change.rollback(prev))} diff --git a/frontend/src/constants/messages.ts b/frontend/src/constants/messages.ts index 159e2a0b..c24def8d 100644 --- a/frontend/src/constants/messages.ts +++ b/frontend/src/constants/messages.ts @@ -63,6 +63,7 @@ export const FALLBACK_MESSAGES = { AUTH_CHECK: "ログイン状態の確認に失敗しました。", GITHUB_OAUTH_START: "GitHub OAuth の開始に失敗しました", GITHUB_LINK: "連携に失敗しました", + PROOFREAD: "文章の校正に失敗しました。", } as const; /** @@ -230,6 +231,23 @@ export const DIFF_DIALOG_MESSAGES = { BASELINE_EMPTY: "保存済みデータがありません。", /** 変更点サイドバーの見出し */ CHANGES_HEADING: "変更点", + /** 変更点+校正を統合したレビュー一覧の見出し */ + REVIEW_HEADING: "変更点・校正", +} as const; + +/** + * 保存確認ダイアログ内の文章校正(誤字脱字・表記ゆれ)セクションの文言。 + * 指摘メッセージ本文は textlint 由来の外部正本なのでここには持たず、そのまま表示する。 + */ +export const PROOFREAD_MESSAGES = { + /** サイドバーの校正セクション見出し。 */ + HEADING: "校正の指摘", + /** 校正処理中の表示。 */ + LOADING: "文章を校正中...", + /** 指摘ゼロ件のときの表示。 */ + NONE: "校正の指摘はありません。", + /** セクションの補足(保存はブロックしない旨)。 */ + HINT: "保存はブロックされません。気になる箇所のみ修正してください。", } as const; /** 左右 diff で「変更なし領域」を畳んだときの展開ラベル(件数を埋め込む)。 */ diff --git a/frontend/src/hooks/career/useProofread.test.ts b/frontend/src/hooks/career/useProofread.test.ts new file mode 100644 index 00000000..1688928b --- /dev/null +++ b/frontend/src/hooks/career/useProofread.test.ts @@ -0,0 +1,95 @@ +import { act, renderHook } from "@testing-library/react"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +import type { CareerFormState } from "../../payloadBuilders"; +import type { ProofreadIssue } from "../../proofread/types"; +import { useProofread } from "./useProofread"; + +vi.mock("../../proofread/proofreadClient", () => ({ + proofreadCareerForm: vi.fn(), +})); + +import { proofreadCareerForm } from "../../proofread/proofreadClient"; + +const mockProofread = proofreadCareerForm as unknown as ReturnType; + +const form: CareerFormState = { + full_name: "山田 太郎", + career_summary: "サマリー", + self_pr: "自己PR", + experiences: [], + qualifications: [], +}; + +const issue: ProofreadIssue = { + fieldId: "self_pr", + fieldLabel: "自己PR", + ruleId: "prh", + message: "javascript => JavaScript", + severity: "warning", + line: 1, + column: 1, + index: 0, + excerpt: "javascript", +}; + +beforeEach(() => { + mockProofread.mockReset(); + mockProofread.mockResolvedValue([issue]); + vi.useFakeTimers(); +}); + +afterEach(() => { + vi.useRealTimers(); +}); + +describe("useProofread", () => { + it("成功: enabled の間フォームを校正し指摘を返す", async () => { + const { result } = renderHook(() => useProofread(form, true)); + await act(async () => { + await vi.advanceTimersByTimeAsync(350); + }); + expect(mockProofread).toHaveBeenCalledTimes(1); + expect(result.current.issues).toEqual([issue]); + expect(result.current.proofreading).toBe(false); + expect(result.current.error).toBeNull(); + }); + + it("失敗: reject したらエラーを立て指摘を空にする", async () => { + mockProofread.mockRejectedValue(new Error("校正失敗")); + const { result } = renderHook(() => useProofread(form, true)); + await act(async () => { + await vi.advanceTimersByTimeAsync(350); + }); + expect(result.current.error).toBe("校正失敗"); + expect(result.current.issues).toEqual([]); + expect(result.current.proofreading).toBe(false); + }); + + it("無効化中(enabled=false)は校正せず、結果は空のまま", async () => { + const { result } = renderHook(() => useProofread(form, false)); + await act(async () => { + await vi.advanceTimersByTimeAsync(350); + }); + expect(mockProofread).not.toHaveBeenCalled(); + expect(result.current.issues).toEqual([]); + expect(result.current.error).toBeNull(); + }); + + it("enabled が false に変わると前回の指摘をクリアする", async () => { + const { result, rerender } = renderHook( + ({ enabled }: { enabled: boolean }) => useProofread(form, enabled), + { initialProps: { enabled: true } }, + ); + await act(async () => { + await vi.advanceTimersByTimeAsync(350); + }); + expect(result.current.issues).toEqual([issue]); + + rerender({ enabled: false }); + await act(async () => { + await vi.advanceTimersByTimeAsync(10); + }); + expect(result.current.issues).toEqual([]); + }); +}); diff --git a/frontend/src/hooks/career/useProofread.ts b/frontend/src/hooks/career/useProofread.ts new file mode 100644 index 00000000..02095ee7 --- /dev/null +++ b/frontend/src/hooks/career/useProofread.ts @@ -0,0 +1,72 @@ +import { useEffect, useState } from "react"; + +import { FALLBACK_MESSAGES } from "../../constants/messages"; +import type { CareerFormState } from "../../payloadBuilders"; +import { proofreadCareerForm } from "../../proofread/proofreadClient"; +import type { ProofreadIssue } from "../../proofread/types"; + +/** 校正の取得状態。 */ +export type ProofreadState = { + /** 校正指摘の一覧(フィールド横断・収集順)。 */ + issues: ProofreadIssue[]; + /** 校正処理中フラグ。 */ + proofreading: boolean; + /** 校正失敗時のメッセージ。 */ + error: string | null; +}; + +/** + * デバウンス。ダイアログ表示中に form が変わるのはロールバック操作のみだが、 + * 校正は worker 往復があるため軽くまとめる。 + */ +const DEBOUNCE_MS = 300; + +/** + * 保存確認ダイアログが開いている間(`enabled`)、編集中フォームを校正するフック。 + * + * - ロールバックで form が変わるたびに再校正する(デバウンス付き)。 + * - ダイアログを閉じたら結果をクリアし、次回開いた時に前回の指摘を残さない。 + * - `react-hooks/set-state-in-effect` を避けるため、状態更新はすべて setTimeout 内で行う。 + */ +export function useProofread(form: CareerFormState, enabled: boolean): ProofreadState { + const [issues, setIssues] = useState([]); + const [proofreading, setProofreading] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + let active = true; + const handle = setTimeout( + () => { + if (!active) return; + if (!enabled) { + setIssues([]); + setError(null); + setProofreading(false); + return; + } + setProofreading(true); + setError(null); + proofreadCareerForm(form) + .then((result) => { + if (active) setIssues(result); + }) + .catch((err) => { + if (active) { + setIssues([]); + setError(err instanceof Error ? err.message : FALLBACK_MESSAGES.PROOFREAD); + } + }) + .finally(() => { + if (active) setProofreading(false); + }); + }, + enabled ? DEBOUNCE_MS : 0, + ); + return () => { + active = false; + clearTimeout(handle); + }; + }, [enabled, form]); + + return { issues, proofreading, error }; +} diff --git a/frontend/src/proofread/collectCareerTexts.test.ts b/frontend/src/proofread/collectCareerTexts.test.ts new file mode 100644 index 00000000..d1d6200d --- /dev/null +++ b/frontend/src/proofread/collectCareerTexts.test.ts @@ -0,0 +1,123 @@ +import { describe, expect, it } from "vitest"; + +import { + blankCareerClient, + blankCareerExperience, + blankCareerProject, +} from "../constants"; +import type { CareerExperienceForm, CareerFormState } from "../payloadBuilders"; +import { collectCareerTexts } from "./collectCareerTexts"; + +/** 必要なフィールドだけ上書きした職歴を作る。 */ +function makeExperience(overrides: Partial): CareerExperienceForm { + return { ...blankCareerExperience, ...overrides }; +} + +function makeForm(overrides: Partial): CareerFormState { + return { + full_name: "", + career_summary: "", + self_pr: "", + experiences: [], + qualifications: [], + ...overrides, + }; +} + +describe("collectCareerTexts", () => { + it("トップレベルの職務要約・自己PRを収集する(氏名は対象外)", () => { + const items = collectCareerTexts( + makeForm({ full_name: "山田 太郎", career_summary: "要約です", self_pr: "PRです" }), + ); + const ids = items.map((i) => i.id); + expect(ids).toContain("career_summary"); + expect(ids).toContain("self_pr"); + expect(ids).not.toContain("full_name"); + }); + + it("空白のみの値は除外する", () => { + const items = collectCareerTexts(makeForm({ career_summary: " ", self_pr: "" })); + expect(items).toEqual([]); + }); + + it("非IT企業は description を収集し、clients は辿らない", () => { + const exp = makeExperience({ + company: "非IT社", + business_description: "事業", + start_date: "2020-01", + is_it_company: false, + description: "詳細テキスト", + clients: [{ ...blankCareerClient, has_client: true, name: "取引先A" }], + }); + const items = collectCareerTexts(makeForm({ experiences: [exp] })); + const ids = items.map((i) => i.id); + expect(ids).toContain("experiences.0.company"); + expect(ids).toContain("experiences.0.business_description"); + expect(ids).toContain("experiences.0.description"); + // 非IT企業なので取引先配下は収集しない + expect(ids.some((id) => id.includes("clients"))).toBe(false); + }); + + it("IT企業は取引先名・案件の自由記述を辿り、ラベルはパンくずになる", () => { + const exp = makeExperience({ + company: "IT社", + business_description: "事業", + start_date: "2020-01", + is_it_company: true, + clients: [ + { + ...blankCareerClient, + has_client: true, + name: "取引先A", + projects: [ + { + ...blankCareerProject, + name: "案件X", + role: "リーダー", + description: "案件の説明", + }, + ], + }, + ], + }); + const items = collectCareerTexts(makeForm({ experiences: [exp] })); + const byId = new Map(items.map((i) => [i.id, i])); + expect(byId.has("experiences.0.clients.0.name")).toBe(true); + expect(byId.has("experiences.0.clients.0.projects.0.name")).toBe(true); + expect(byId.has("experiences.0.clients.0.projects.0.role")).toBe(true); + expect(byId.has("experiences.0.clients.0.projects.0.description")).toBe(true); + // パンくず: 職歴1 > 取引先1 > プロジェクト1 > 案件詳細 + expect(byId.get("experiences.0.clients.0.projects.0.description")?.label).toContain("職歴1"); + expect(byId.get("experiences.0.clients.0.projects.0.description")?.label).toContain( + "プロジェクト1", + ); + }); + + it("休暇の取引先は休暇内容のみ収集する", () => { + const exp = makeExperience({ + company: "IT社", + business_description: "事業", + start_date: "2020-01", + is_it_company: true, + clients: [ + { + ...blankCareerClient, + is_vacation: true, + vacation_start_date: "2021-01", + vacation_description: "育児休暇を取得", + }, + ], + }); + const items = collectCareerTexts(makeForm({ experiences: [exp] })); + const ids = items.map((i) => i.id); + expect(ids).toContain("experiences.0.clients.0.vacation_description"); + expect(ids.some((id) => id.includes("projects"))).toBe(false); + }); + + it("資格は名称を収集する", () => { + const items = collectCareerTexts( + makeForm({ qualifications: [{ acquired_date: "2020-01", name: "基本情報技術者" }] }), + ); + expect(items.map((i) => i.id)).toContain("qualifications.0.name"); + }); +}); diff --git a/frontend/src/proofread/collectCareerTexts.ts b/frontend/src/proofread/collectCareerTexts.ts new file mode 100644 index 00000000..3c353cbe --- /dev/null +++ b/frontend/src/proofread/collectCareerTexts.ts @@ -0,0 +1,106 @@ +/** + * 職務経歴フォーム(`CareerFormState`)から校正対象のテキスト項目を平坦化する純粋関数。 + * + * ## 方針 + * - 校正は「保存される自由記述」を対象にする。日付・数値・真偽・選択値(技術スタック等)は除外する。 + * - 収集条件は `payloadBuilders.ts` の包含判定(`experienceIncluded` / `clientIncluded` / + * `projectIncluded`)を再利用し、payload に載らない(=保存されない)行は校正しない。 + * - `id`(ドット区切りパス)と `label`(パンくず)は `utils/careerDiff.ts` の体系に揃える。 + * そうすることで、ダイアログのサイドバーで「変更点」と「校正の指摘」が同じラベルで並ぶ。 + * + * 空白のみの値は除外する(指摘の意味がないため)。 + */ +import { CAREER_DIFF_LABELS as L, DIFF_DIALOG_MESSAGES as D } from "../constants/messages"; +import { + clientIncluded, + experienceIncluded, + projectIncluded, + type CareerFormState, +} from "../payloadBuilders"; +import type { CareerTextItem } from "./types"; + +/** ラベルセグメントを区切り文字で連結する(careerDiff の joinLabel と同一)。 */ +function joinLabel(segments: string[]): string { + return segments.join(D.PATH_SEPARATOR); +} + +/** 値が非空(trim 後)なら 1 項目 push する。 */ +function pushText( + items: CareerTextItem[], + id: string, + labelSegments: string[], + value: string, +): void { + if (!value.trim()) return; + items.push({ id, label: joinLabel(labelSegments), value }); +} + +/** + * フォームを走査し、校正対象テキストを順番(フォームの並び)どおりに収集する。 + */ +export function collectCareerTexts(form: CareerFormState): CareerTextItem[] { + const items: CareerTextItem[] = []; + + // 並び順は PDF レイアウト(職務要約 → 職務経歴 → 資格 → 自己PR)に合わせ、 + // 左右ペイン・変更点リストと校正セクションの縦順を一致させる。 + pushText(items, "career_summary", [L.CAREER_SUMMARY], form.career_summary); + + form.experiences.forEach((exp, expIndex) => { + if (!experienceIncluded(exp)) return; + const expSeg = [`${L.EXPERIENCE}${expIndex + 1}`]; + const expPath = `experiences.${expIndex}`; + + pushText(items, `${expPath}.company`, [...expSeg, L.COMPANY], exp.company); + pushText( + items, + `${expPath}.business_description`, + [...expSeg, L.BUSINESS_DESCRIPTION], + exp.business_description, + ); + + if (!exp.is_it_company) { + pushText(items, `${expPath}.description`, [...expSeg, L.DESCRIPTION], exp.description); + return; + } + + exp.clients.forEach((client, clientIndex) => { + if (!clientIncluded(client)) return; + const clientSeg = [...expSeg, `${L.CLIENT}${clientIndex + 1}`]; + const clientPath = `${expPath}.clients.${clientIndex}`; + + if (client.is_vacation) { + pushText( + items, + `${clientPath}.vacation_description`, + [...clientSeg, L.VACATION_DESCRIPTION], + client.vacation_description, + ); + return; + } + + if (client.has_client) { + pushText(items, `${clientPath}.name`, [...clientSeg, L.CLIENT_NAME], client.name); + } + + client.projects.forEach((proj, projIndex) => { + if (!projectIncluded(proj)) return; + const projSeg = [...clientSeg, `${L.PROJECT}${projIndex + 1}`]; + const projPath = `${clientPath}.projects.${projIndex}`; + + pushText(items, `${projPath}.name`, [...projSeg, L.PROJECT_NAME], proj.name); + pushText(items, `${projPath}.role`, [...projSeg, L.ROLE], proj.role); + pushText(items, `${projPath}.description`, [...projSeg, L.PROJECT_DESCRIPTION], proj.description); + }); + }); + }); + + form.qualifications.forEach((qual, index) => { + const qualSeg = [`${L.QUALIFICATION}${index + 1}`]; + pushText(items, `qualifications.${index}.name`, [...qualSeg, L.QUALIFICATION_NAME], qual.name); + }); + + // 自己PR は PDF 上で最後に来るため末尾に収集する。 + pushText(items, "self_pr", [L.SELF_PR], form.self_pr); + + return items; +} diff --git a/frontend/src/proofread/issueFormat.test.ts b/frontend/src/proofread/issueFormat.test.ts new file mode 100644 index 00000000..4e8c472e --- /dev/null +++ b/frontend/src/proofread/issueFormat.test.ts @@ -0,0 +1,70 @@ +import { describe, expect, it } from "vitest"; + +import { buildExcerpt, groupIssuesByField, mapSeverity } from "./issueFormat"; +import type { ProofreadIssue } from "./types"; + +describe("mapSeverity", () => { + it("0=info / 1=warning / 2 以上=error に写像する", () => { + expect(mapSeverity(0)).toBe("info"); + expect(mapSeverity(1)).toBe("warning"); + expect(mapSeverity(2)).toBe("error"); + expect(mapSeverity(3)).toBe("error"); + }); +}); + +describe("buildExcerpt", () => { + it("指摘箇所の前後を切り出す(両端が途切れると省略記号を付ける)", () => { + // 40 文字。半径 12 なので index=20 だと前後とも途切れる。 + const text = "あいうえおかきくけこさしすせそたちつてとアイウエオカキクケコサシスセソタチツテト"; + const excerpt = buildExcerpt(text, 20, 1); + expect(excerpt).toContain("カ"); + expect(excerpt.startsWith("…")).toBe(true); + expect(excerpt.endsWith("…")).toBe(true); + }); + + it("先頭付近は前側の省略記号を付けない", () => { + const excerpt = buildExcerpt("短いテキスト", 0, 1); + expect(excerpt.startsWith("…")).toBe(false); + expect(excerpt).toContain("短い"); + }); + + it("改行・連続空白は 1 つの空白に潰す", () => { + const excerpt = buildExcerpt("行1\n\n 行2", 0, 1); + expect(excerpt).not.toContain("\n"); + expect(excerpt).toBe("行1 行2"); + }); + + it("空文字なら空を返す", () => { + expect(buildExcerpt("", 0, 1)).toBe(""); + }); +}); + +describe("groupIssuesByField", () => { + const makeIssue = (fieldId: string, fieldLabel: string, message: string): ProofreadIssue => ({ + fieldId, + fieldLabel, + ruleId: "prh", + message, + severity: "warning", + line: 1, + column: 1, + index: 0, + excerpt: "", + }); + + it("フィールド単位でグルーピングし、入力順を保つ", () => { + const issues = [ + makeIssue("self_pr", "自己PR", "A"), + makeIssue("career_summary", "職務要約", "B"), + makeIssue("self_pr", "自己PR", "C"), + ]; + const groups = groupIssuesByField(issues); + expect(groups.map((g) => g.fieldId)).toEqual(["self_pr", "career_summary"]); + expect(groups[0].issues.map((i) => i.message)).toEqual(["A", "C"]); + expect(groups[1].issues.map((i) => i.message)).toEqual(["B"]); + }); + + it("空配列なら空グループ", () => { + expect(groupIssuesByField([])).toEqual([]); + }); +}); diff --git a/frontend/src/proofread/issueFormat.ts b/frontend/src/proofread/issueFormat.ts new file mode 100644 index 00000000..4fbccf4b --- /dev/null +++ b/frontend/src/proofread/issueFormat.ts @@ -0,0 +1,59 @@ +/** + * 校正結果(textlint メッセージ)を `ProofreadIssue` へ整形する純粋関数群。 + * + * worker 本体(`proofread.worker.ts`)から呼ばれるが、textlint/kuromoji に依存しないため + * 単体テスト可能。worker 経路をモックしても、ここはそのままテストできる。 + */ +import type { ProofreadIssue, ProofreadSeverity } from "./types"; + +/** 抜粋に含める指摘箇所前後の文字数。 */ +const EXCERPT_RADIUS = 12; + +/** textlint の severity 数値(0=info / 1=warning / 2=error)を文字列へ写像する。 */ +export function mapSeverity(severity: number): ProofreadSeverity { + if (severity >= 2) return "error"; + if (severity === 1) return "warning"; + return "info"; +} + +/** + * フィールド本文から指摘箇所の前後を抜き出す。 + * - index 周辺を `EXCERPT_RADIUS` 文字ずつ切り出し、端が途切れる場合は省略記号を付ける。 + * - 改行は空白に潰して 1 行で見せる。 + */ +export function buildExcerpt(text: string, index: number, length = 1): string { + if (!text) return ""; + const safeIndex = Math.max(0, Math.min(index, text.length)); + const start = Math.max(0, safeIndex - EXCERPT_RADIUS); + const end = Math.min(text.length, safeIndex + Math.max(1, length) + EXCERPT_RADIUS); + const slice = text.slice(start, end).replace(/\s+/g, " ").trim(); + const prefix = start > 0 ? "…" : ""; + const suffix = end < text.length ? "…" : ""; + return `${prefix}${slice}${suffix}`; +} + +/** フィールド単位にグルーピングした指摘。サイドバー表示で使う。 */ +export type ProofreadGroup = { + fieldId: string; + fieldLabel: string; + issues: ProofreadIssue[]; +}; + +/** + * 指摘をフィールド単位へグルーピングする。 + * 入力順(= 収集順 = フォームの並び)を保ったままグループ化し、各グループ内も入力順を保つ。 + */ +export function groupIssuesByField(issues: ProofreadIssue[]): ProofreadGroup[] { + const groups: ProofreadGroup[] = []; + const indexById = new Map(); + for (const issue of issues) { + let pos = indexById.get(issue.fieldId); + if (pos === undefined) { + pos = groups.length; + indexById.set(issue.fieldId, pos); + groups.push({ fieldId: issue.fieldId, fieldLabel: issue.fieldLabel, issues: [] }); + } + groups[pos].issues.push(issue); + } + return groups; +} diff --git a/frontend/src/proofread/prh-it-terms.yml b/frontend/src/proofread/prh-it-terms.yml new file mode 100644 index 00000000..5e33ce76 --- /dev/null +++ b/frontend/src/proofread/prh-it-terms.yml @@ -0,0 +1,98 @@ +# IT 用語の表記ゆれ辞書(prh)。 +# 職務経歴書で頻出する固有名詞・技術用語の正規化に絞る。 +# `expected` が正、`patterns` が誤記(自動マッチ)。誤検出を避けるため過剰なパターンは登録しない。 +version: 1 +rules: + # 言語・ランタイム + - expected: JavaScript + patterns: + - javascript + - Javascript + - java script + - expected: TypeScript + patterns: + - typescript + - Typescript + - type script + - expected: Node.js + patterns: + - node.js + - Nodejs + - NodeJS + - node js + - expected: Python + patterns: + - python + - expected: Ruby + patterns: + - ruby + - expected: PHP + patterns: + - Php + - expected: Golang + patterns: + - golang + # フレームワーク・ライブラリ + - expected: React + patterns: + - react + - expected: Vue.js + patterns: + - vue.js + - Vuejs + - expected: Next.js + patterns: + - next.js + - Nextjs + - expected: Django + patterns: + - django + - expected: FastAPI + patterns: + - fastapi + - Fastapi + # インフラ・ツール + - expected: Docker + patterns: + - docker + - expected: Kubernetes + patterns: + - kubernetes + - expected: GitHub + patterns: + - github + - Github + - git hub + - expected: GitLab + patterns: + - gitlab + - Gitlab + - expected: MySQL + patterns: + - mysql + - Mysql + - expected: PostgreSQL + patterns: + - postgresql + - Postgresql + - postgres + - expected: Redis + patterns: + - redis + # 一般的な表記ゆれ + - expected: ソフトウェア + patterns: + - ソフトウエア + - expected: ハードウェア + patterns: + - ハードウエア + - expected: インターフェース + patterns: + - インタフェース + - インターフェイス + - expected: データベース + patterns: + - データーベース + - expected: ディレクトリ + patterns: + - ディレクトリー diff --git a/frontend/src/proofread/proofread.worker.ts b/frontend/src/proofread/proofread.worker.ts new file mode 100644 index 00000000..166cb761 --- /dev/null +++ b/frontend/src/proofread/proofread.worker.ts @@ -0,0 +1,190 @@ +/// +/** + * 文章校正 Web Worker。textlint kernel + 技術文書プリセット + prh をこの中で組み立て、 + * メインスレッドから渡されたテキスト項目を校正して `ProofreadIssue[]` を返す。 + * + * ## ブラウザ統合のポイント(ハマりどころ) + * - kuromoji(形態素解析)の辞書はブラウザに fs が無いため、`public/kuromoji-dict/` を + * 静的配信し、kuromojin が参照する `globalThis.kuromojin.dicPath` に URL を注入する。 + * kuromojin は `typeof window !== "undefined"` を前提とするため、worker では `window` も補う。 + * - kuromoji の辞書ロード(数 MB)に失敗しても機能停止させない。辞書を使うルール + * (二重助詞・冗長表現など)は preload 成功時のみ登録し、失敗時は prh + 形態素非依存 + * ルールだけで動作させる(グレースフルデグラデーション)。 + * - prh ルールはファイル読み込み不可なので、YAML を `?raw` 文字列で読み込み `ruleContents` で渡す。 + */ +// 最初に import すること(textlint/kuromoji 依存の評価前にグローバルを用意する)。 +import "./worker-env-polyfill"; + +import { TextlintKernel } from "@textlint/kernel"; +import type { TextlintKernelPlugin, TextlintKernelRule } from "@textlint/kernel"; + +import prhRule from "textlint-rule-prh"; + +import { buildExcerpt, mapSeverity } from "./issueFormat"; +import prhYaml from "./prh-it-terms.yml?raw"; +import type { + CareerTextItem, + ProofreadIssue, + ProofreadRequest, + ProofreadResponse, +} from "./types"; + +/** + * textlint ルール / プラグインは CJS↔ESM 相互運用で `default` が多重ラップされることがある。 + * 本体(関数 もしくは `{ linter }` / `{ create }` を持つオブジェクト)まで掘り下げる。 + */ +function unwrapModule(mod: unknown): T { + let current = mod as Record | unknown; + for (let i = 0; i < 5; i += 1) { + if (typeof current === "function") return current as T; + if ( + current && + typeof current === "object" && + ("linter" in current || "create" in current || "fixer" in current) + ) { + return current as T; + } + if (current && typeof current === "object" && "default" in current) { + current = (current as { default: unknown }).default; + continue; + } + break; + } + return current as T; +} + +const kernel = new TextlintKernel(); + +/** + * 技術文書プリセットのうち kuromoji(形態素解析)に依存するルール ID。 + * 辞書 preload に失敗した場合、これらを除外して機能停止を避ける。 + */ +const KUROMOJI_RULE_IDS = new Set([ + "max-ten", + "no-double-negative-ja", + "no-doubled-conjunction", + "no-doubled-conjunctive-particle-ga", + "no-doubled-joshi", + "no-dropping-the-ra", + "ja-no-weak-phrase", + "ja-no-successive-word", + "ja-no-abusage", + "ja-no-redundant-expression", + // 念のため漢数字ルールも辞書依存側に寄せる(誤検出より安全側)。 + "arabic-kanji-numbers", +]); + +/** 技術文書プリセットの import 形({ rules, rulesConfig })。 */ +type PresetModule = { + rules: Record; + rulesConfig: Record; +}; + +/** + * プリセットから kernel 用のルール記述子を組み立てる。 + * `includeKuromoji=false` のときは形態素解析依存ルールを除外する。 + * prh(表記ゆれ)はプリセット外なので常に末尾へ足す。 + */ +function buildRules(preset: PresetModule, includeKuromoji: boolean): TextlintKernelRule[] { + const rules: TextlintKernelRule[] = []; + for (const [ruleId, rule] of Object.entries(preset.rules)) { + if (!includeKuromoji && KUROMOJI_RULE_IDS.has(ruleId)) continue; + const options = preset.rulesConfig[ruleId]; + rules.push({ + ruleId, + rule: unwrapModule(rule), + // rulesConfig の値が false/true(無効/デフォルト)の場合は options を渡さない。 + ...(options && typeof options === "object" ? { options } : {}), + }); + } + rules.push({ ruleId: "prh", rule: unwrapModule(prhRule), options: { ruleContents: [prhYaml] } }); + return rules; +} + +/** kernel.lintText に渡す構築済み設定。 */ +type ProofreadConfig = { + plugins: TextlintKernelPlugin[]; + rules: TextlintKernelRule[]; +}; + +/** テキストプラグイン(.txt 解析)と全ルールを 1 回だけ構築してキャッシュする。 */ +let setupPromise: Promise | null = null; + +async function setup(): Promise { + const [textPlugin, presetModule] = await Promise.all([ + import("@textlint/textlint-plugin-text"), + import("textlint-rule-preset-ja-technical-writing"), + ]); + const preset = (("default" in presetModule ? presetModule.default : presetModule) ?? + presetModule) as PresetModule; + const plugins: TextlintKernelPlugin[] = [ + { pluginId: "text", plugin: unwrapModule(textPlugin) }, + ]; + + // 辞書を preload。成功時のみ kuromoji 依存ルールを含める。 + let includeKuromoji = false; + try { + const kuromojin = await import("kuromojin"); + await kuromojin.getTokenizer(); + includeKuromoji = true; + } catch { + // 辞書ロード失敗時は形態素非依存ルール + prh のみで継続(機能停止させない)。 + includeKuromoji = false; + } + + return { plugins, rules: buildRules(preset, includeKuromoji) }; +} + +function ensureSetup() { + if (!setupPromise) { + // setup 失敗(依存ロード不能)も握りつぶさず、各リクエストで再試行できるよう null に戻す。 + setupPromise = setup().catch((err) => { + setupPromise = null; + throw err; + }); + } + return setupPromise; +} + +/** 1 テキスト項目を校正し、ProofreadIssue 配列へ整形する。 */ +async function proofreadItem( + item: CareerTextItem, + config: ProofreadConfig, +): Promise { + const result = await kernel.lintText(item.value, { + ext: ".txt", + plugins: config.plugins, + rules: config.rules, + }); + return result.messages.map((message) => ({ + fieldId: item.id, + fieldLabel: item.label, + ruleId: message.ruleId, + message: message.message, + severity: mapSeverity(message.severity), + line: message.line, + column: message.column, + index: message.index, + excerpt: buildExcerpt(item.value, message.index), + })); +} + +self.onmessage = async (event: MessageEvent) => { + const data = event.data; + if (!data || data.type !== "proofread") return; + const { requestId, items } = data; + try { + const config = await ensureSetup(); + const nested = await Promise.all(items.map((item) => proofreadItem(item, config))); + const issues = nested.flat(); + const response: ProofreadResponse = { type: "result", requestId, issues }; + self.postMessage(response); + } catch (err) { + const response: ProofreadResponse = { + type: "error", + requestId, + message: err instanceof Error ? err.message : String(err), + }; + self.postMessage(response); + } +}; diff --git a/frontend/src/proofread/proofreadClient.ts b/frontend/src/proofread/proofreadClient.ts new file mode 100644 index 00000000..e74cd253 --- /dev/null +++ b/frontend/src/proofread/proofreadClient.ts @@ -0,0 +1,58 @@ +/** + * 校正 worker のメインスレッド側サービス。 + * + * - worker は初回呼び出し時にのみ遅延生成する(textlint / kuromoji 一式は worker チャンクへ + * 分離され、初期バンドル・初回描画には載らない)。 + * - 各リクエストに連番 `requestId` を振り、応答を id で突合してレースを防ぐ。 + * - 収集テキストが 0 件なら worker を起動せず空配列を返す。 + */ +import type { CareerFormState } from "../payloadBuilders"; +import { collectCareerTexts } from "./collectCareerTexts"; +import type { ProofreadIssue, ProofreadRequest, ProofreadResponse } from "./types"; + +let worker: Worker | null = null; +let nextRequestId = 1; + +/** worker を遅延生成する(テストでは本モジュールごとモックするため、ここは実行されない)。 */ +function getWorker(): Worker { + if (!worker) { + worker = new Worker(new URL("./proofread.worker.ts", import.meta.url), { type: "module" }); + } + return worker; +} + +/** + * 編集中フォームの全テキスト項目を校正する。 + * 収集 0 件なら即 `[]`。それ以外は worker へ投げ、当該 requestId の応答を待つ。 + */ +export function proofreadCareerForm(form: CareerFormState): Promise { + const items = collectCareerTexts(form); + if (items.length === 0) return Promise.resolve([]); + + const activeWorker = getWorker(); + const requestId = nextRequestId; + nextRequestId += 1; + + return new Promise((resolve, reject) => { + const cleanup = () => { + activeWorker.removeEventListener("message", onMessage); + activeWorker.removeEventListener("error", onError); + }; + const onMessage = (event: MessageEvent) => { + const data = event.data; + if (!data || data.requestId !== requestId) return; + cleanup(); + if (data.type === "result") resolve(data.issues); + else reject(new Error(data.message)); + }; + const onError = (event: ErrorEvent) => { + cleanup(); + reject(event.error instanceof Error ? event.error : new Error(event.message)); + }; + activeWorker.addEventListener("message", onMessage); + activeWorker.addEventListener("error", onError); + + const request: ProofreadRequest = { type: "proofread", requestId, items }; + activeWorker.postMessage(request); + }); +} diff --git a/frontend/src/proofread/textlint-modules.d.ts b/frontend/src/proofread/textlint-modules.d.ts new file mode 100644 index 00000000..900eab8c --- /dev/null +++ b/frontend/src/proofread/textlint-modules.d.ts @@ -0,0 +1,7 @@ +/** + * textlint ルール群の型宣言。これらの npm パッケージは型定義を同梱しておらず、 + * 校正 worker はルール本体を `unwrapModule` 経由で扱うため、ここで any として宣言する。 + * (ルールの内部構造に型安全は不要 — kernel に渡すだけ)。 + */ +// textlint-rule-* 系(プリセット同梱の個別ルール)をまとめてワイルドカード宣言する。 +declare module "textlint-rule-*"; diff --git a/frontend/src/proofread/types.ts b/frontend/src/proofread/types.ts new file mode 100644 index 00000000..8baa0c37 --- /dev/null +++ b/frontend/src/proofread/types.ts @@ -0,0 +1,52 @@ +/** + * 文章校正(誤字脱字・表記ゆれ)機能の型 Single Source of Truth。 + * + * メインスレッド(hook / コンポーネント)は textlint や kuromoji を一切知らず、 + * この `ProofreadIssue` 配列だけを介して worker とやり取りする。エンジンを差し替えても + * この型が変わらなければ UI 側は影響を受けない(疎結合の境界)。 + */ + +/** 指摘の深刻度。textlint の severity 数値(0=info / 1=warning / 2=error)を文字列へ写像したもの。 */ +export type ProofreadSeverity = "info" | "warning" | "error"; + +/** 校正対象となる 1 テキスト項目(フォームから平坦化したもの)。 */ +export type CareerTextItem = { + /** フォーム上のドット区切りパス(例: "experiences.0.description")。careerDiff の path と揃える。 */ + id: string; + /** 人間可読ラベル(パンくず。例: "職歴1 > 詳細")。 */ + label: string; + /** 校正にかける本文。 */ + value: string; +}; + +/** 1 件の校正指摘。フィールド単位にグルーピングして表示する。 */ +export type ProofreadIssue = { + /** 指摘が属するフィールドの id(`CareerTextItem.id`)。 */ + fieldId: string; + /** 指摘が属するフィールドのラベル(`CareerTextItem.label`)。 */ + fieldLabel: string; + /** textlint のルール ID(例: "prh" / "ja-no-mixed-period")。 */ + ruleId: string; + /** 指摘メッセージ(textlint 由来の外部正本。そのまま表示してよい)。 */ + message: string; + severity: ProofreadSeverity; + /** フィールド本文内の行・列(1 始まり)。 */ + line: number; + column: number; + /** フィールド本文内の文字オフセット(0 始まり)。 */ + index: number; + /** 指摘箇所の前後を抜き出した短い抜粋(UI のコンテキスト表示用)。 */ + excerpt: string; +}; + +/** メインスレッド → worker への校正リクエスト。 */ +export type ProofreadRequest = { + type: "proofread"; + requestId: number; + items: CareerTextItem[]; +}; + +/** worker → メインスレッドへの応答。 */ +export type ProofreadResponse = + | { type: "result"; requestId: number; issues: ProofreadIssue[] } + | { type: "error"; requestId: number; message: string }; diff --git a/frontend/src/proofread/worker-env-polyfill.ts b/frontend/src/proofread/worker-env-polyfill.ts new file mode 100644 index 00000000..29b27908 --- /dev/null +++ b/frontend/src/proofread/worker-env-polyfill.ts @@ -0,0 +1,46 @@ +/** + * 校正 worker 用の最小グローバル補完。worker の **最初** に import して副作用を効かせる + * (textlint / kuromoji 系の依存が評価・実行時に参照する node/ブラウザのグローバルを先に用意する)。 + * + * - `process`: async / textlint 依存が `process.env` / `process.nextTick` を参照する。worker には無い。 + * - `window`: kuromojin は辞書パス解決で `typeof window !== "undefined"` を前提とする。worker には無い。 + * - `window.kuromojin.dicPath`: 静的配信した辞書(public/kuromoji-dict/)の URL を注入する。 + */ +type MinimalProcess = { + env: Record; + nextTick: (cb: (...args: unknown[]) => void, ...args: unknown[]) => void; + cwd: () => string; + platform: string; + version: string; + argv: string[]; +}; + +const g = globalThis as unknown as { + process?: Partial; + window?: unknown; + kuromojin?: { dicPath: string }; +}; + +if (typeof g.process === "undefined") { + g.process = {}; +} +// 一部の textlint 依存(prh 経由の ja-no-abusage 等)が参照する API を最小実装で補う。 +const proc = g.process as Partial; +proc.env ??= {}; +proc.nextTick ??= (cb, ...args) => { + void Promise.resolve().then(() => cb(...args)); +}; +proc.cwd ??= () => "/"; +proc.platform ??= "browser"; +proc.version ??= ""; +proc.argv ??= []; + +if (typeof g.window === "undefined") { + g.window = globalThis; +} + +// 辞書の静的配信パスを kuromojin に渡す。 +// 注意: ルート相対パスにする(`http://…` のような絶対 URL を渡すと、kuromoji 内部の +// path.join(ブラウザでは path-browserify)が `://` を `:/` に潰して壊れる)。 +// XHR はこのルート相対パスを worker の origin 基準で解決する。 +g.kuromojin = { dicPath: "/kuromoji-dict" }; diff --git a/frontend/src/utils/careerDiff.ts b/frontend/src/utils/careerDiff.ts index 8a32b407..c58e541b 100644 --- a/frontend/src/utils/careerDiff.ts +++ b/frontend/src/utils/careerDiff.ts @@ -280,9 +280,10 @@ export function buildCareerChanges( ): CareerChange[] { const changes: CareerChange[] = []; + // 並び順は PDF レイアウト(氏名 → 職務要約 → 職務経歴 → 資格 → 自己PR)に合わせる。 + // 左右ペインとサイドバー(変更点 / 校正)の縦順が一致し、突合しやすくなる。 pushScalar(changes, [], L.FULL_NAME, ["full_name"], form.full_name, baseline.full_name); pushScalar(changes, [], L.CAREER_SUMMARY, ["career_summary"], form.career_summary, baseline.career_summary); - pushScalar(changes, [], L.SELF_PR, ["self_pr"], form.self_pr, baseline.self_pr); diffArray( changes, form.experiences, baseline.experiences, ["experiences"], [], @@ -293,5 +294,7 @@ export function buildCareerChanges( L.QUALIFICATION, (q) => q.name, diffQualification, ); + pushScalar(changes, [], L.SELF_PR, ["self_pr"], form.self_pr, baseline.self_pr); + return changes; } diff --git a/frontend/src/utils/careerReview.test.ts b/frontend/src/utils/careerReview.test.ts new file mode 100644 index 00000000..6418a1b6 --- /dev/null +++ b/frontend/src/utils/careerReview.test.ts @@ -0,0 +1,78 @@ +import { describe, expect, it } from "vitest"; + +import { buildReviewEntries, comparePaths } from "./careerReview"; +import type { CareerChange } from "./careerDiff"; +import type { ProofreadIssue } from "../proofread/types"; + +function change(path: (string | number)[], label: string): CareerChange { + return { path, label, kind: "modified", oldValue: "", newValue: "", rollback: (f) => f }; +} +function issue(fieldId: string, fieldLabel: string, message: string): ProofreadIssue { + return { + fieldId, + fieldLabel, + ruleId: "prh", + message, + severity: "warning", + line: 1, + column: 1, + index: 0, + excerpt: "", + }; +} + +describe("comparePaths", () => { + it("トップレベルは PDF 順(自己PR が資格より後)", () => { + expect(comparePaths("self_pr", "qualifications.0.name")).toBeGreaterThan(0); + expect(comparePaths("career_summary", "experiences.0.company")).toBeLessThan(0); + }); + + it("親は子より前", () => { + expect(comparePaths("experiences.0", "experiences.0.company")).toBeLessThan(0); + }); + + it("配列 index は数値順", () => { + expect(comparePaths("experiences.0.company", "experiences.1.company")).toBeLessThan(0); + }); + + it("コンテナ内のフィールドは PDF 順(company が business_description より前)", () => { + expect(comparePaths("experiences.0.company", "experiences.0.business_description")).toBeLessThan(0); + }); +}); + +describe("buildReviewEntries", () => { + it("同一パスの差分と校正を 1 エントリに統合する", () => { + const entries = buildReviewEntries( + [change(["career_summary"], "職務要約")], + [issue("career_summary", "職務要約", "javascript => JavaScript")], + ); + expect(entries).toHaveLength(1); + expect(entries[0].changes).toHaveLength(1); + expect(entries[0].issues).toHaveLength(1); + }); + + it("PDF レイアウト順に並ぶ(自己PRが末尾、職歴は資格より前)", () => { + const entries = buildReviewEntries( + [change(["self_pr"], "自己PR"), change(["full_name"], "氏名")], + [ + issue("self_pr", "自己PR", "x"), + issue("qualifications.0.name", "資格1 > 資格名", "y"), + issue("experiences.0.company", "職歴1 > 会社名", "z"), + ], + ); + const order = entries.map((e) => e.path); + expect(order[0]).toBe("full_name"); + expect(order[order.length - 1]).toBe("self_pr"); + expect(order.indexOf("experiences.0.company")).toBeLessThan(order.indexOf("qualifications.0.name")); + }); + + it("差分のみ・校正のみの項目もそれぞれエントリになる", () => { + const entries = buildReviewEntries( + [change(["full_name"], "氏名")], + [issue("experiences.0.description", "職歴1 > 詳細", "冗長")], + ); + expect(entries.map((e) => e.path)).toEqual(["full_name", "experiences.0.description"]); + expect(entries[0].issues).toHaveLength(0); + expect(entries[1].changes).toHaveLength(0); + }); +}); diff --git a/frontend/src/utils/careerReview.ts b/frontend/src/utils/careerReview.ts new file mode 100644 index 00000000..c65e389a --- /dev/null +++ b/frontend/src/utils/careerReview.ts @@ -0,0 +1,122 @@ +/** + * 保存確認ダイアログ右サイドバーの「レビュー項目」を組み立てる純関数。 + * + * 変更点(差分)と校正指摘を**フィールド単位で1本のリストに統合**し、PDF レイアウトと + * 同じ縦順(氏名 → 職務要約 → 職務経歴 → 資格 → 自己PR、各コンテナ内も PDF 準拠)に並べる。 + * これにより左右ペイン(PDF)とサイドバーの並びが一致し、上から順に突合できる。 + */ +import { groupIssuesByField } from "../proofread/issueFormat"; +import type { ProofreadIssue } from "../proofread/types"; +import type { CareerChange } from "./careerDiff"; + +/** 1 フィールド分のレビュー項目(差分と校正をまとめて持つ)。 */ +export type ReviewEntry = { + /** フィールドのドット区切りパス(スクロール・key 用)。 */ + path: string; + /** 人間可読ラベル(パンくず)。 */ + label: string; + /** このフィールドの差分(通常 0〜1 件)。 */ + changes: CareerChange[]; + /** このフィールドの校正指摘。 */ + issues: ProofreadIssue[]; +}; + +/** トップレベル項目の並び(PDF レイアウト順)。 */ +const TOP_ORDER = ["full_name", "career_summary", "experiences", "qualifications", "self_pr"]; + +/** 配列コンテナごとのフィールド並び(careerDiff の走査順=PDF 準拠)。 */ +const CONTAINER_FIELD_ORDER: Record = { + experiences: [ + "company", + "business_description", + "start_date", + "end_date", + "is_current", + "employee_count", + "capital", + "capital_unit", + "is_it_company", + "description", + "clients", + ], + clients: [ + "name", + "has_client", + "is_vacation", + "vacation_start_date", + "vacation_end_date", + "vacation_is_current", + "vacation_description", + "projects", + ], + projects: ["name", "role", "description", "team", "periods", "technology_stacks", "phases"], + qualifications: ["name", "acquired_date"], +}; + +/** 未知のセグメントを既知フィールドより後ろへ寄せる基準値(文字コードで安定ソート)。 */ +const UNKNOWN_FIELD_RANK_BASE = 400; +/** コンテナの並びが特定できない名前付きセグメントのランク(末尾側へ)。 */ +const UNKNOWN_CONTAINER_FIELD_RANK = 500; + +/** 既知の並びにあればその index、無ければ末尾側(文字コードで安定ソート)に寄せる。 */ +function orderIndex(list: string[], seg: string): number { + const i = list.indexOf(seg); + return i >= 0 ? i : UNKNOWN_FIELD_RANK_BASE + (seg.charCodeAt(0) || 0); +} + +/** + * パスを「並び順を表す数値タプル」に変換する。 + * - 先頭セグメント: トップレベル順 + * - 数値セグメント: 配列 index + * - 名前付きセグメント: 直近の配列名(2 つ前)から決まるコンテナのフィールド順 + */ +function rankTuple(path: string): number[] { + const segs = path.split("."); + return segs.map((seg, i) => { + if (i === 0) return orderIndex(TOP_ORDER, seg); + if (/^\d+$/.test(seg)) return Number(seg); + const containerName = i >= 2 && /^\d+$/.test(segs[i - 1]) ? segs[i - 2] : null; + const order = containerName ? CONTAINER_FIELD_ORDER[containerName] : null; + return order ? orderIndex(order, seg) : UNKNOWN_CONTAINER_FIELD_RANK; + }); +} + +/** 2 つのパスを PDF レイアウト順で比較する(親は子より前)。 */ +export function comparePaths(a: string, b: string): number { + const ra = rankTuple(a); + const rb = rankTuple(b); + const len = Math.min(ra.length, rb.length); + for (let i = 0; i < len; i++) { + if (ra[i] !== rb[i]) return ra[i] - rb[i]; + } + return ra.length - rb.length; +} + +/** + * 差分と校正指摘をフィールド単位に統合し、PDF レイアウト順に並べたレビュー項目を返す。 + * 同一パスの差分・校正は 1 エントリにまとまる。差分のみ・校正のみの項目もそれぞれ 1 エントリ。 + */ +export function buildReviewEntries( + changes: CareerChange[], + issues: ProofreadIssue[], +): ReviewEntry[] { + const byPath = new Map(); + + const getOrCreate = (path: string, label: string): ReviewEntry => { + let entry = byPath.get(path); + if (!entry) { + entry = { path, label, changes: [], issues: [] }; + byPath.set(path, entry); + } + return entry; + }; + + for (const change of changes) { + getOrCreate(change.path.join("."), change.label).changes.push(change); + } + for (const group of groupIssuesByField(issues)) { + getOrCreate(group.fieldId, group.fieldLabel).issues.push(...group.issues); + } + + return [...byPath.values()].sort((a, b) => comparePaths(a.path, b.path)); +} diff --git a/frontend/src/utils/diffHighlight.test.ts b/frontend/src/utils/diffHighlight.test.ts index b0051a00..27926121 100644 --- a/frontend/src/utils/diffHighlight.test.ts +++ b/frontend/src/utils/diffHighlight.test.ts @@ -144,6 +144,45 @@ describe("foldUnchanged", () => { const html = '
a
'; expect(foldUnchanged(html, buildPathKindMap([]))).toBe(html); }); + + it("校正指摘のある項目は(差分が無くても)畳まずに残す", () => { + const html = + '
A
' + + '
B
'; + // 差分は experiences.0 のみ。experiences.1 は校正指摘があるので畳まれない。 + const map = buildPathKindMap([change(["experiences", 0, "company"], "modified")]); + const proofread = new Set(["experiences.1.company"]); + const out = foldUnchanged(html, map, proofread); + const doc = new DOMParser().parseFromString(out, "text/html"); + // 校正指摘のある experiences.1 は details の外に残る + expect(doc.querySelector('details [data-unit="experiences.1"]')).toBeNull(); + expect(doc.querySelector('[data-unit="experiences.1"]')).not.toBeNull(); + }); +}); + +describe("annotateHtml(校正マーク)", () => { + it("校正指摘のある data-fp に diff-proofread を付ける", () => { + const html = + '
要約
PR
'; + const out = annotateHtml(html, buildPathKindMap([]), new Set(["self_pr"])); + const doc = new DOMParser().parseFromString(out, "text/html"); + expect(doc.querySelector('[data-fp="self_pr"]')?.className).toContain("diff-proofread"); + // 指摘の無い career_summary には付かない + expect(doc.querySelector('[data-fp="career_summary"]')?.className).toBe(""); + }); + + it("差分(黄)と校正(青)は同じノードに併記される", () => { + const html = '
PR
'; + const out = annotateHtml( + html, + buildPathKindMap([change(["self_pr"], "modified")]), + new Set(["self_pr"]), + ); + const cls = new DOMParser().parseFromString(out, "text/html").querySelector('[data-fp="self_pr"]') + ?.className; + expect(cls).toContain("diff-modified"); + expect(cls).toContain("diff-proofread"); + }); }); describe("injectRemovedPlaceholders", () => { diff --git a/frontend/src/utils/diffHighlight.ts b/frontend/src/utils/diffHighlight.ts index 2723413e..9a8e07e9 100644 --- a/frontend/src/utils/diffHighlight.ts +++ b/frontend/src/utils/diffHighlight.ts @@ -54,9 +54,16 @@ function matchKind(nodePath: string, map: Map): ChangeKind | * * 変更が無ければ sanitize のみ行う。`dangerouslySetInnerHTML` には渡さず、 * iframe の `srcDoc` に埋め込む前提(呼び出し側で隔離)。 + * + * `proofreadFieldIds` を渡すと、その data-fp に一致するノードへ校正マーク(青波線)の + * クラス `diff-proofread` を付ける。編集中ペインで「校正指摘のあるフィールド」を示す用途。 */ -export function annotateHtml(html: string, map: Map): string { - if (map.size === 0) return DOMPurify.sanitize(html); +export function annotateHtml( + html: string, + map: Map, + proofreadFieldIds: Set = new Set(), +): string { + if (map.size === 0 && proofreadFieldIds.size === 0) return DOMPurify.sanitize(html); const doc = new DOMParser().parseFromString(html, "text/html"); doc.body.querySelectorAll("[data-fp]").forEach((node) => { @@ -66,6 +73,10 @@ export function annotateHtml(html: string, map: Map): string if (kind) { node.classList.add("diff-mark", KIND_CLASS[kind]); } + // 校正指摘のあるフィールドは青波線(差分の背景色と重ねても潰れない)。 + if (proofreadFieldIds.has(fp)) { + node.classList.add("diff-proofread"); + } }); // DOMPurify は既定で data-* 属性・class を保持する(ALLOW_DATA_ATTR=true)。 return DOMPurify.sanitize(doc.body.innerHTML); @@ -76,6 +87,14 @@ function unitChanged(unitPath: string, map: Map): boolean { return matchKind(unitPath, map) !== null; } +/** 項目(data-unit)配下に校正指摘のあるフィールドが含まれるか。 */ +function unitHasProofread(unitPath: string, proofreadFieldIds: Set): boolean { + for (const fp of proofreadFieldIds) { + if (fp === unitPath || fp.startsWith(`${unitPath}.`)) return true; + } + return false; +} + /** * prefix 直下で「先頭(最小 index)の既存兄弟(data-unit)」を探す。 * @@ -178,22 +197,31 @@ export function injectRemovedPlaceholders(html: string, changes: CareerChange[]) * - `
` はネイティブの開閉なので、スクリプト無効の sandbox iframe 内でも展開できる。 * * 変更が無ければ(map 空)何もしない。annotateHtml の後段に適用する前提。 + * + * `proofreadFieldIds` を渡すと、校正指摘を含む項目は(差分が無くても)畳まずに残す + * (編集中ペインで青マークが折りたたみに隠れないようにする)。 */ -export function foldUnchanged(html: string, map: Map): string { +export function foldUnchanged( + html: string, + map: Map, + proofreadFieldIds: Set = new Set(), +): string { if (map.size === 0) return html; const doc = new DOMParser().parseFromString(html, "text/html"); const units = Array.from(doc.body.querySelectorAll("[data-unit]")); - // 畳み根: 自身が未変更 かつ 最も近い祖先 unit が「変更あり or 不在」のもの。 + // 畳み根: 自身が未変更 かつ 校正指摘も無い かつ 最も近い祖先 unit が「変更あり or 不在」のもの。 const collapseRoots = new Set(); for (const u of units) { const path = u.getAttribute("data-unit"); - if (!path || unitChanged(path, map)) continue; + if (!path || unitChanged(path, map) || unitHasProofread(path, proofreadFieldIds)) continue; const parentUnit = u.parentElement?.closest("[data-unit]"); if (parentUnit) { const parentPath = parentUnit.getAttribute("data-unit"); - if (parentPath && !unitChanged(parentPath, map)) continue; // 祖先ごと畳まれる + if (parentPath && !unitChanged(parentPath, map) && !unitHasProofread(parentPath, proofreadFieldIds)) { + continue; // 祖先ごと畳まれる + } } collapseRoots.add(u); } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index fb44ea1f..d0c6b54e 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,10 +1,69 @@ /// -import { defineConfig } from "vite"; +import { createReadStream } from "node:fs"; +import { join, normalize } from "node:path"; +import { defineConfig, type Plugin } from "vite"; import react from "@vitejs/plugin-react"; +/** + * kuromoji(校正 worker の形態素解析)辞書を dev サーバーで「生の gzip バイト列」として配信する。 + * + * 既定の静的配信は `.gz` 拡張子を見て `Content-Encoding: gzip` を付けるため、ブラウザが + * 自動展開してしまい、kuromoji 側の再 gunzip が「invalid file signature」で失敗する。 + * ここでは Content-Encoding を付けず application/octet-stream で素のまま返し、 + * kuromoji が自前で gunzip できるようにする(本番 Cloudflare Pages 用は public/_headers で同等指定)。 + */ +function kuromojiDictRaw(): Plugin { + const publicDir = join(process.cwd(), "public"); + return { + name: "kuromoji-dict-raw", + configureServer(server) { + server.middlewares.use((req, res, next) => { + const url = req.url?.split("?")[0] ?? ""; + if (!url.startsWith("/kuromoji-dict/") || !url.endsWith(".dat.gz")) { + next(); + return; + } + // 先頭スラッシュを除いて確実に publicDir 相対で解決する(join の絶対パス扱いを回避)。 + // パストラバーサル防止のため normalize 後に publicDir 配下であることを担保する。 + const relativePath = url.replace(/^\/+/, ""); + const filePath = normalize(join(publicDir, relativePath)); + if (!filePath.startsWith(publicDir)) { + res.statusCode = 403; + res.end(); + return; + } + res.setHeader("Content-Type", "application/octet-stream"); + res.setHeader("Cache-Control", "no-cache"); + createReadStream(filePath) + .on("error", () => next()) + .pipe(res); + }); + }, + }; +} + export default defineConfig({ - plugins: [react()], + plugins: [react(), kuromojiDictRaw()], base: "/", + resolve: { + alias: { + // 校正 worker が使う textlint / kuromoji 依存が参照する node 組み込みのうち、 + // 実行時に実際に呼ばれる path / os / assert はブラウザ実装へ差し替える。 + // fs は本機能で経路を踏まない(YAML は ?raw 文字列で渡す)ため、 + // Vite 既定の空モジュール externalize に任せる(別途エイリアスしない)。 + path: "path-browserify", + "node:path": "path-browserify", + os: "os-browserify/browser", + "node:os": "os-browserify/browser", + assert: "assert", + "node:assert": "assert", + }, + }, + // worker は動的 import でルールを分割ロードする(コード分割)。 + // iife/umd は code-splitting 非対応なので ES モジュール形式で出力する。 + worker: { + format: "es", + }, server: { host: "0.0.0.0", port: 5173,