├── .github └── workflows │ └── ci.yml ├── .gitignore ├── README.md ├── __tests__ ├── routes.spec.ts ├── setup.ts └── utils.ts ├── example ├── .gitignore ├── index.html ├── package.json ├── pnpm-lock.yaml ├── src │ ├── App.tsx │ ├── main.tsx │ ├── pages │ │ ├── 404.tsx │ │ ├── bar │ │ │ └── [dynamic].jsx │ │ ├── components │ │ │ └── button.jsx │ │ ├── contact.jsx │ │ ├── error.tsx │ │ ├── foo │ │ │ ├── _type.jsx │ │ │ ├── bar.jsx │ │ │ ├── index.jsx │ │ │ └── layout.jsx │ │ ├── hyphen-name.tsx │ │ ├── index.jsx │ │ ├── layout.tsx │ │ ├── sync.tsx │ │ └── utils.tsx │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── index.ts ├── package.json ├── pnpm-lock.yaml ├── tsconfig.json ├── vite.config.ts └── vitest.config.ts /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - dev 8 | tags-ignore: 9 | - v* 10 | paths-ignore: 11 | - "**/README.md" 12 | pull_request: 13 | types: 14 | - open 15 | - reopened 16 | - synchronize 17 | - ready_for_review 18 | paths-ignore: 19 | - "**/README.md" 20 | 21 | concurrency: 22 | group: ${{ github.workflow }}-${{ github.event.number || github.sha }} 23 | cancel-in-progress: true 24 | 25 | jobs: 26 | build: 27 | timeout-minutes: 20 28 | runs-on: ${{ matrix.os }} 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | os: [ubuntu-latest, macos-latest] 33 | 34 | steps: 35 | - uses: actions/checkout@v3 36 | 37 | - name: Install pnpm 38 | uses: pnpm/action-setup@v4 39 | with: 40 | version: 6.0.2 41 | 42 | - name: Set node version to ${{ matrix.node_version }} 43 | uses: actions/setup-node@v4 44 | with: 45 | node-version: 20 46 | 47 | - name: Install dependencies 48 | run: | 49 | pnpm install 50 | cd example 51 | pnpm install 52 | cd .. 53 | 54 | - name: Build 55 | run: pnpm build 56 | 57 | - name: Test 58 | run: pnpm test 59 | 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vite-plugin-react-views 2 | A vite plugin based on File System for creating routes automatically. 3 | 4 | Some rules you need to know: 5 | - Requirement: `react-router-dom@^6.9` 6 | - All files in conventional directory will become routes, except empty files and excluded files. 7 | - For code splitting, all routes will be imported dynamically by [lazy](https://reactrouter.com/en/dev/route/lazy), except layout route in root directory. 8 | - you can export `'Component'、'ErrorBoundary'、'loader'、'action', 'handle'、'shouldRevalidate'、'errorElement'、'id'` in every route file 9 | - A file starts with a `_` character or wraps by `[]` will be `dynamic route`. 10 | - Every file named `layout` in directory will become layout route. 11 | - The file named `404` in root directory will become `No Match(404) Route`. 12 | 13 | ### Installation 14 | ```js 15 | npm install vite-plugin-react-views --save-dev 16 | ``` 17 | 18 | ### Usage 19 | ```js 20 | // vite.config.js 21 | import { defineConfig } from 'vite' 22 | import react from '@vitejs/plugin-react' 23 | import router from 'vite-plugin-react-views' 24 | 25 | export default defineConfig({ 26 | plugins: [react(), router()] 27 | }) 28 | 29 | // App.jsx 30 | import { RouterProvider, createBrowserRouter } from 'react-router-dom' 31 | // Requirement: import routes 32 | import routes from 'route-views' 33 | 34 | const router = createBrowserRouter(routes) 35 | 36 | export default function App() { 37 | return ( 38 | 41 | ) 42 | } 43 | ``` 44 | 45 | ### Options 46 | 47 | - dir: string 48 | 49 | default: `'src/pages'` 50 | 51 | A directory path for crawling. 52 | 53 | - exclude(path): boolean 54 | 55 | A file will not become a route if return true. 56 | 57 | - sync(path): boolean 58 | 59 | A route will be imported synchronously if return true. 60 | 61 | - extensions: string[] 62 | 63 | default: `['js', 'jsx', 'ts', 'tsx']` 64 | 65 | Filename extensions which will be scanned and imported as route elements. 66 | 67 | ### Typescript 68 | ```js 69 | // src/vite-env.d.ts 70 | /// 71 | 72 | declare module 'route-views' { 73 | const routes: (import('react-router-dom').RouteObject)[]; 74 | 75 | export default routes; 76 | } 77 | ``` 78 | 79 | ### License 80 | MIT 81 | -------------------------------------------------------------------------------- /__tests__/routes.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from 'vitest' 2 | import { page } from './utils' 3 | import fs from 'node:fs' 4 | import path from 'node:path' 5 | 6 | test('/', async () => { 7 | expect(await page.textContent('.layout')).toBe('layout') 8 | expect(await page.textContent('.content')).toBe('index') 9 | }) 10 | 11 | test('Test root layout\'s loader', async () => { 12 | expect(await page.textContent('.layout-loader-data')).toBe('root') 13 | }) 14 | 15 | test('Test synchronous route', async () => { 16 | expect((await page.content()).includes('id="sync"')).toBeTruthy() 17 | }) 18 | 19 | test('Nested layout should not be imported synchronously', async () => { 20 | expect((await page.content()).includes('id="foo_layout"')).toBeFalsy() 21 | }) 22 | 23 | test('Should not create Route for excluded directory', async () => { 24 | await page.click('.excluded-components') 25 | expect(await page.textContent('.content')).toContain('404 Not Found') 26 | await page.goBack() 27 | }) 28 | 29 | test('/contact', async () => { 30 | await page.click('.contact') 31 | expect(await page.textContent('.layout')).toBe('layout') 32 | expect(await page.textContent('.content')).toBe('contact') 33 | }) 34 | 35 | test('/bar/:dynamic (test dynamic route format `[name]`)', async () => { 36 | await page.click('.bar-dynamic') 37 | expect(await page.textContent('.layout')).toBe('layout') 38 | expect(await page.textContent('.dynamic')).toBe('dynamic') 39 | }) 40 | 41 | test('/foo', async () => { 42 | await page.click('.foo') 43 | expect(await page.textContent('.layout')).toBe('layout') 44 | expect(await page.textContent('.foo-layout')).toBe('layout-foo') 45 | expect(await page.textContent('.foo-content')).toBe('foo') 46 | }) 47 | 48 | test('/foo/bar', async () => { 49 | await page.click('.foo-bar') 50 | expect(await page.textContent('.layout')).toBe('layout') 51 | expect(await page.textContent('.foo-layout')).toBe('layout-foo') 52 | expect(await page.textContent('.foo-content')).toBe('bar') 53 | }) 54 | 55 | test('/foo/:type', async () => { 56 | await page.click('.foo-type') 57 | expect(await page.textContent('.layout')).toBe('layout') 58 | expect(await page.textContent('.foo-layout')).toBe('layout-foo') 59 | expect(await page.textContent('.foo-content')).toBe('a') 60 | }) 61 | 62 | test('hyphen-name', async () => { 63 | await page.click('.hyphen-name') 64 | expect(await page.textContent('.layout')).toBe('layout') 65 | expect(await page.textContent('.content')).toBe('hyphen-name') 66 | }) 67 | 68 | test('index', async () => { 69 | await page.click('.index') 70 | expect(await page.textContent('.layout')).toBe('layout') 71 | expect(await page.textContent('.content')).toBe('index') 72 | }) 73 | 74 | test('/utils (exclude)', async () => { 75 | await page.click('.utils') 76 | expect(await page.textContent('.content')).toContain('404 Not Found') 77 | 78 | await page.goBack() 79 | expect(await page.textContent('.layout')).toBe('layout') 80 | expect(await page.textContent('.content')).toBe('index') 81 | }) 82 | 83 | test('/error', async () => { 84 | await page.click('.error') 85 | expect(await page.textContent('.route-error')).toContain('Route Error') 86 | 87 | await page.goBack() 88 | }) 89 | 90 | if (!process.env.VITEST_BUILD) { 91 | test('HMR', async () => { 92 | await page.click('.about') 93 | expect(await page.textContent('.content')).toContain('404 Not Found') 94 | 95 | const aboutFile = path.join(process.cwd(), 'example/src/pages/about.jsx') 96 | fs.writeFileSync(aboutFile, '') 97 | fs.writeFileSync(aboutFile, `export function Component() { 98 | return
about
99 | }`) 100 | 101 | expect(await page.textContent('.layout')).toBe('layout') 102 | expect(await page.textContent('.content')).toBe('about') 103 | 104 | fs.rmSync(aboutFile) 105 | }) 106 | } 107 | 108 | 109 | -------------------------------------------------------------------------------- /__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | import { chromium } from 'playwright-chromium' 3 | import { createServer, build, preview, loadConfigFromFile, mergeConfig } from 'vite' 4 | import { beforeAll } from 'vitest' 5 | import type { InlineConfig, ViteDevServer } from 'vite' 6 | import type { BrowserServer, Page, Browser } from 'playwright-chromium' 7 | 8 | const isBuild = !!process.env.VITEST_BUILD 9 | let testConfig: InlineConfig 10 | let server: ViteDevServer 11 | 12 | let browserServer: BrowserServer 13 | let browser: Browser 14 | export let page: Page 15 | 16 | beforeAll(async () => { 17 | browserServer = await chromium.launchServer() 18 | browser = await chromium.connect(browserServer.wsEndpoint()) 19 | page = await browser.newPage() 20 | 21 | try { 22 | await startPrepare() 23 | } catch (e) { 24 | await server?.close() 25 | throw e 26 | } 27 | 28 | return async () => { 29 | await server?.close() 30 | await page.close() 31 | await browser.close() 32 | await browserServer.close() 33 | } 34 | }) 35 | 36 | async function startPrepare() { 37 | const testDir = path.join(process.cwd(), 'example') 38 | 39 | const res = await loadConfigFromFile( 40 | { 41 | command: isBuild ? 'build' : 'serve', 42 | mode: isBuild ? 'production' : 'development' 43 | }, 44 | undefined, 45 | testDir 46 | ) 47 | 48 | const options: InlineConfig = { 49 | root: testDir, 50 | configFile: false, 51 | build: { 52 | target: 'esnext' 53 | } 54 | } 55 | 56 | testConfig = mergeConfig(options, res!.config) 57 | if (isBuild) { 58 | await build(testConfig) 59 | const previewServer = await preview(testConfig) 60 | await page.goto(previewServer.resolvedUrls.local[0]!) 61 | } else { 62 | server = await (await createServer(testConfig)).listen() 63 | await page.goto(`http://localhost:${server.config.server.port}`) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /__tests__/utils.ts: -------------------------------------------------------------------------------- 1 | export * from './setup' 2 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "v6.9", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "react-router-dom": "^6.10.0" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^22.1.0", 18 | "@types/react": "^18.3.3", 19 | "@types/react-dom": "^18.3.0", 20 | "@vitejs/plugin-react-swc": "^3.2.0", 21 | "typescript": "^5.5.4", 22 | "vite": "^5.3.5", 23 | "vite-plugin-react-views": "link:.." 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | react: 12 | specifier: ^18.2.0 13 | version: 18.3.1 14 | react-dom: 15 | specifier: ^18.2.0 16 | version: 18.3.1(react@18.3.1) 17 | react-router-dom: 18 | specifier: ^6.10.0 19 | version: 6.26.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 20 | devDependencies: 21 | '@types/node': 22 | specifier: ^22.1.0 23 | version: 22.1.0 24 | '@types/react': 25 | specifier: ^18.3.3 26 | version: 18.3.3 27 | '@types/react-dom': 28 | specifier: ^18.3.0 29 | version: 18.3.0 30 | '@vitejs/plugin-react-swc': 31 | specifier: ^3.2.0 32 | version: 3.7.0(vite@5.3.5(@types/node@22.1.0)) 33 | typescript: 34 | specifier: ^5.5.4 35 | version: 5.5.4 36 | vite: 37 | specifier: ^5.3.5 38 | version: 5.3.5(@types/node@22.1.0) 39 | vite-plugin-react-views: 40 | specifier: link:.. 41 | version: link:.. 42 | 43 | packages: 44 | 45 | '@esbuild/aix-ppc64@0.21.5': 46 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 47 | engines: {node: '>=12'} 48 | cpu: [ppc64] 49 | os: [aix] 50 | 51 | '@esbuild/android-arm64@0.21.5': 52 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 53 | engines: {node: '>=12'} 54 | cpu: [arm64] 55 | os: [android] 56 | 57 | '@esbuild/android-arm@0.21.5': 58 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 59 | engines: {node: '>=12'} 60 | cpu: [arm] 61 | os: [android] 62 | 63 | '@esbuild/android-x64@0.21.5': 64 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 65 | engines: {node: '>=12'} 66 | cpu: [x64] 67 | os: [android] 68 | 69 | '@esbuild/darwin-arm64@0.21.5': 70 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 71 | engines: {node: '>=12'} 72 | cpu: [arm64] 73 | os: [darwin] 74 | 75 | '@esbuild/darwin-x64@0.21.5': 76 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 77 | engines: {node: '>=12'} 78 | cpu: [x64] 79 | os: [darwin] 80 | 81 | '@esbuild/freebsd-arm64@0.21.5': 82 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 83 | engines: {node: '>=12'} 84 | cpu: [arm64] 85 | os: [freebsd] 86 | 87 | '@esbuild/freebsd-x64@0.21.5': 88 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 89 | engines: {node: '>=12'} 90 | cpu: [x64] 91 | os: [freebsd] 92 | 93 | '@esbuild/linux-arm64@0.21.5': 94 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 95 | engines: {node: '>=12'} 96 | cpu: [arm64] 97 | os: [linux] 98 | 99 | '@esbuild/linux-arm@0.21.5': 100 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 101 | engines: {node: '>=12'} 102 | cpu: [arm] 103 | os: [linux] 104 | 105 | '@esbuild/linux-ia32@0.21.5': 106 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 107 | engines: {node: '>=12'} 108 | cpu: [ia32] 109 | os: [linux] 110 | 111 | '@esbuild/linux-loong64@0.21.5': 112 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 113 | engines: {node: '>=12'} 114 | cpu: [loong64] 115 | os: [linux] 116 | 117 | '@esbuild/linux-mips64el@0.21.5': 118 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 119 | engines: {node: '>=12'} 120 | cpu: [mips64el] 121 | os: [linux] 122 | 123 | '@esbuild/linux-ppc64@0.21.5': 124 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 125 | engines: {node: '>=12'} 126 | cpu: [ppc64] 127 | os: [linux] 128 | 129 | '@esbuild/linux-riscv64@0.21.5': 130 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 131 | engines: {node: '>=12'} 132 | cpu: [riscv64] 133 | os: [linux] 134 | 135 | '@esbuild/linux-s390x@0.21.5': 136 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 137 | engines: {node: '>=12'} 138 | cpu: [s390x] 139 | os: [linux] 140 | 141 | '@esbuild/linux-x64@0.21.5': 142 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 143 | engines: {node: '>=12'} 144 | cpu: [x64] 145 | os: [linux] 146 | 147 | '@esbuild/netbsd-x64@0.21.5': 148 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 149 | engines: {node: '>=12'} 150 | cpu: [x64] 151 | os: [netbsd] 152 | 153 | '@esbuild/openbsd-x64@0.21.5': 154 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 155 | engines: {node: '>=12'} 156 | cpu: [x64] 157 | os: [openbsd] 158 | 159 | '@esbuild/sunos-x64@0.21.5': 160 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 161 | engines: {node: '>=12'} 162 | cpu: [x64] 163 | os: [sunos] 164 | 165 | '@esbuild/win32-arm64@0.21.5': 166 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 167 | engines: {node: '>=12'} 168 | cpu: [arm64] 169 | os: [win32] 170 | 171 | '@esbuild/win32-ia32@0.21.5': 172 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 173 | engines: {node: '>=12'} 174 | cpu: [ia32] 175 | os: [win32] 176 | 177 | '@esbuild/win32-x64@0.21.5': 178 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 179 | engines: {node: '>=12'} 180 | cpu: [x64] 181 | os: [win32] 182 | 183 | '@remix-run/router@1.19.0': 184 | resolution: {integrity: sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==} 185 | engines: {node: '>=14.0.0'} 186 | 187 | '@rollup/rollup-android-arm-eabi@4.20.0': 188 | resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} 189 | cpu: [arm] 190 | os: [android] 191 | 192 | '@rollup/rollup-android-arm64@4.20.0': 193 | resolution: {integrity: sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==} 194 | cpu: [arm64] 195 | os: [android] 196 | 197 | '@rollup/rollup-darwin-arm64@4.20.0': 198 | resolution: {integrity: sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==} 199 | cpu: [arm64] 200 | os: [darwin] 201 | 202 | '@rollup/rollup-darwin-x64@4.20.0': 203 | resolution: {integrity: sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==} 204 | cpu: [x64] 205 | os: [darwin] 206 | 207 | '@rollup/rollup-linux-arm-gnueabihf@4.20.0': 208 | resolution: {integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==} 209 | cpu: [arm] 210 | os: [linux] 211 | libc: [glibc] 212 | 213 | '@rollup/rollup-linux-arm-musleabihf@4.20.0': 214 | resolution: {integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==} 215 | cpu: [arm] 216 | os: [linux] 217 | libc: [musl] 218 | 219 | '@rollup/rollup-linux-arm64-gnu@4.20.0': 220 | resolution: {integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==} 221 | cpu: [arm64] 222 | os: [linux] 223 | libc: [glibc] 224 | 225 | '@rollup/rollup-linux-arm64-musl@4.20.0': 226 | resolution: {integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==} 227 | cpu: [arm64] 228 | os: [linux] 229 | libc: [musl] 230 | 231 | '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': 232 | resolution: {integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==} 233 | cpu: [ppc64] 234 | os: [linux] 235 | libc: [glibc] 236 | 237 | '@rollup/rollup-linux-riscv64-gnu@4.20.0': 238 | resolution: {integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==} 239 | cpu: [riscv64] 240 | os: [linux] 241 | libc: [glibc] 242 | 243 | '@rollup/rollup-linux-s390x-gnu@4.20.0': 244 | resolution: {integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==} 245 | cpu: [s390x] 246 | os: [linux] 247 | libc: [glibc] 248 | 249 | '@rollup/rollup-linux-x64-gnu@4.20.0': 250 | resolution: {integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==} 251 | cpu: [x64] 252 | os: [linux] 253 | libc: [glibc] 254 | 255 | '@rollup/rollup-linux-x64-musl@4.20.0': 256 | resolution: {integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==} 257 | cpu: [x64] 258 | os: [linux] 259 | libc: [musl] 260 | 261 | '@rollup/rollup-win32-arm64-msvc@4.20.0': 262 | resolution: {integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==} 263 | cpu: [arm64] 264 | os: [win32] 265 | 266 | '@rollup/rollup-win32-ia32-msvc@4.20.0': 267 | resolution: {integrity: sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==} 268 | cpu: [ia32] 269 | os: [win32] 270 | 271 | '@rollup/rollup-win32-x64-msvc@4.20.0': 272 | resolution: {integrity: sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==} 273 | cpu: [x64] 274 | os: [win32] 275 | 276 | '@swc/core-darwin-arm64@1.7.5': 277 | resolution: {integrity: sha512-Y+bvW9C4/u26DskMbtQKT4FU6QQenaDYkKDi028vDIKAa7v1NZqYG9wmhD/Ih7n5EUy2uJ5I5EWD7WaoLzT6PA==} 278 | engines: {node: '>=10'} 279 | cpu: [arm64] 280 | os: [darwin] 281 | 282 | '@swc/core-darwin-x64@1.7.5': 283 | resolution: {integrity: sha512-AuIbDlcaAhYS6mtF4UqvXgrLeAfXZbVf4pgtgShPbutF80VbCQiIB55zOFz5aZdCpsBVuCWcBq0zLneK+VQKkQ==} 284 | engines: {node: '>=10'} 285 | cpu: [x64] 286 | os: [darwin] 287 | 288 | '@swc/core-linux-arm-gnueabihf@1.7.5': 289 | resolution: {integrity: sha512-99uBPHITRqgGwCXAjHY94VaV3Z40+D2NQNgR1t6xQpO8ZnevI6YSzX6GVZfBnV7+7oisiGkrVEwfIRRa+1s8FA==} 290 | engines: {node: '>=10'} 291 | cpu: [arm] 292 | os: [linux] 293 | 294 | '@swc/core-linux-arm64-gnu@1.7.5': 295 | resolution: {integrity: sha512-xHL3Erlz+OGGCG4h6K2HWiR56H5UYMuBWWPbbUufi2bJpfhuKQy/X3vWffwL8ZVfJmCUwr4/G91GHcm32uYzRg==} 296 | engines: {node: '>=10'} 297 | cpu: [arm64] 298 | os: [linux] 299 | libc: [glibc] 300 | 301 | '@swc/core-linux-arm64-musl@1.7.5': 302 | resolution: {integrity: sha512-5ArGdqvFMszNHdi4a67vopeYq8d1K+FuTWDrblHrAvZFhAyv+GQz2PnKqYOgl0sWmQxsNPfNwBFtxACpUO3Jzg==} 303 | engines: {node: '>=10'} 304 | cpu: [arm64] 305 | os: [linux] 306 | libc: [musl] 307 | 308 | '@swc/core-linux-x64-gnu@1.7.5': 309 | resolution: {integrity: sha512-mSVVV/PFzCGtI1nVQQyx34NwCMgSurF6ZX/me8pUAX054vsE/pSFL66xN+kQOe/1Z/LOd4UmXFkZ/EzOSnYcSg==} 310 | engines: {node: '>=10'} 311 | cpu: [x64] 312 | os: [linux] 313 | libc: [glibc] 314 | 315 | '@swc/core-linux-x64-musl@1.7.5': 316 | resolution: {integrity: sha512-09hY3ZKMUORXVunESKS9yuP78+gQbr759GKHo8wyCdtAx8lCZdEjfI5NtC7/1VqwfeE32/U6u+5MBTVhZTt0AA==} 317 | engines: {node: '>=10'} 318 | cpu: [x64] 319 | os: [linux] 320 | libc: [musl] 321 | 322 | '@swc/core-win32-arm64-msvc@1.7.5': 323 | resolution: {integrity: sha512-B/UDtPI3RlYRFW42xQxOpl6kI/9LtkD7No+XeRIKQTPe15EP2o+rUlv7CmKljVBXgJ8KmaQbZlaEh1YP+QZEEQ==} 324 | engines: {node: '>=10'} 325 | cpu: [arm64] 326 | os: [win32] 327 | 328 | '@swc/core-win32-ia32-msvc@1.7.5': 329 | resolution: {integrity: sha512-BgLesVGmIY6Nub/sURqtSRvWYcbCE/ACfuZB3bZHVKD6nsZJJuOpdB8oC41fZPyc8yZUzL3XTBIifkT2RP+w9w==} 330 | engines: {node: '>=10'} 331 | cpu: [ia32] 332 | os: [win32] 333 | 334 | '@swc/core-win32-x64-msvc@1.7.5': 335 | resolution: {integrity: sha512-CnF557tidLfQRPczcqDJ8x+LBQYsFa0Ra6w2+YU1iFUboaI2jJVuqt3vEChu80y6JiRIBAaaV2L/GawDJh1dIQ==} 336 | engines: {node: '>=10'} 337 | cpu: [x64] 338 | os: [win32] 339 | 340 | '@swc/core@1.7.5': 341 | resolution: {integrity: sha512-qKK0/Ta4qvxs/ok3XyYVPT7OBenwRn1sSINf1cKQTBHPqr7U/uB4k2GTl6JgEs8H4PiJrMTNWfMLTucIoVSfAg==} 342 | engines: {node: '>=10'} 343 | peerDependencies: 344 | '@swc/helpers': '*' 345 | peerDependenciesMeta: 346 | '@swc/helpers': 347 | optional: true 348 | 349 | '@swc/counter@0.1.3': 350 | resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} 351 | 352 | '@swc/types@0.1.12': 353 | resolution: {integrity: sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==} 354 | 355 | '@types/estree@1.0.5': 356 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 357 | 358 | '@types/node@22.1.0': 359 | resolution: {integrity: sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==} 360 | 361 | '@types/prop-types@15.7.12': 362 | resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} 363 | 364 | '@types/react-dom@18.3.0': 365 | resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} 366 | 367 | '@types/react@18.3.3': 368 | resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} 369 | 370 | '@vitejs/plugin-react-swc@3.7.0': 371 | resolution: {integrity: sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA==} 372 | peerDependencies: 373 | vite: ^4 || ^5 374 | 375 | csstype@3.1.3: 376 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 377 | 378 | esbuild@0.21.5: 379 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 380 | engines: {node: '>=12'} 381 | hasBin: true 382 | 383 | fsevents@2.3.3: 384 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 385 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 386 | os: [darwin] 387 | 388 | js-tokens@4.0.0: 389 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 390 | 391 | loose-envify@1.4.0: 392 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 393 | hasBin: true 394 | 395 | nanoid@3.3.7: 396 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 397 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 398 | hasBin: true 399 | 400 | picocolors@1.0.1: 401 | resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} 402 | 403 | postcss@8.4.40: 404 | resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} 405 | engines: {node: ^10 || ^12 || >=14} 406 | 407 | react-dom@18.3.1: 408 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} 409 | peerDependencies: 410 | react: ^18.3.1 411 | 412 | react-router-dom@6.26.0: 413 | resolution: {integrity: sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ==} 414 | engines: {node: '>=14.0.0'} 415 | peerDependencies: 416 | react: '>=16.8' 417 | react-dom: '>=16.8' 418 | 419 | react-router@6.26.0: 420 | resolution: {integrity: sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==} 421 | engines: {node: '>=14.0.0'} 422 | peerDependencies: 423 | react: '>=16.8' 424 | 425 | react@18.3.1: 426 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} 427 | engines: {node: '>=0.10.0'} 428 | 429 | rollup@4.20.0: 430 | resolution: {integrity: sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==} 431 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 432 | hasBin: true 433 | 434 | scheduler@0.23.2: 435 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} 436 | 437 | source-map-js@1.2.0: 438 | resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} 439 | engines: {node: '>=0.10.0'} 440 | 441 | typescript@5.5.4: 442 | resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} 443 | engines: {node: '>=14.17'} 444 | hasBin: true 445 | 446 | undici-types@6.13.0: 447 | resolution: {integrity: sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==} 448 | 449 | vite@5.3.5: 450 | resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==} 451 | engines: {node: ^18.0.0 || >=20.0.0} 452 | hasBin: true 453 | peerDependencies: 454 | '@types/node': ^18.0.0 || >=20.0.0 455 | less: '*' 456 | lightningcss: ^1.21.0 457 | sass: '*' 458 | stylus: '*' 459 | sugarss: '*' 460 | terser: ^5.4.0 461 | peerDependenciesMeta: 462 | '@types/node': 463 | optional: true 464 | less: 465 | optional: true 466 | lightningcss: 467 | optional: true 468 | sass: 469 | optional: true 470 | stylus: 471 | optional: true 472 | sugarss: 473 | optional: true 474 | terser: 475 | optional: true 476 | 477 | snapshots: 478 | 479 | '@esbuild/aix-ppc64@0.21.5': 480 | optional: true 481 | 482 | '@esbuild/android-arm64@0.21.5': 483 | optional: true 484 | 485 | '@esbuild/android-arm@0.21.5': 486 | optional: true 487 | 488 | '@esbuild/android-x64@0.21.5': 489 | optional: true 490 | 491 | '@esbuild/darwin-arm64@0.21.5': 492 | optional: true 493 | 494 | '@esbuild/darwin-x64@0.21.5': 495 | optional: true 496 | 497 | '@esbuild/freebsd-arm64@0.21.5': 498 | optional: true 499 | 500 | '@esbuild/freebsd-x64@0.21.5': 501 | optional: true 502 | 503 | '@esbuild/linux-arm64@0.21.5': 504 | optional: true 505 | 506 | '@esbuild/linux-arm@0.21.5': 507 | optional: true 508 | 509 | '@esbuild/linux-ia32@0.21.5': 510 | optional: true 511 | 512 | '@esbuild/linux-loong64@0.21.5': 513 | optional: true 514 | 515 | '@esbuild/linux-mips64el@0.21.5': 516 | optional: true 517 | 518 | '@esbuild/linux-ppc64@0.21.5': 519 | optional: true 520 | 521 | '@esbuild/linux-riscv64@0.21.5': 522 | optional: true 523 | 524 | '@esbuild/linux-s390x@0.21.5': 525 | optional: true 526 | 527 | '@esbuild/linux-x64@0.21.5': 528 | optional: true 529 | 530 | '@esbuild/netbsd-x64@0.21.5': 531 | optional: true 532 | 533 | '@esbuild/openbsd-x64@0.21.5': 534 | optional: true 535 | 536 | '@esbuild/sunos-x64@0.21.5': 537 | optional: true 538 | 539 | '@esbuild/win32-arm64@0.21.5': 540 | optional: true 541 | 542 | '@esbuild/win32-ia32@0.21.5': 543 | optional: true 544 | 545 | '@esbuild/win32-x64@0.21.5': 546 | optional: true 547 | 548 | '@remix-run/router@1.19.0': {} 549 | 550 | '@rollup/rollup-android-arm-eabi@4.20.0': 551 | optional: true 552 | 553 | '@rollup/rollup-android-arm64@4.20.0': 554 | optional: true 555 | 556 | '@rollup/rollup-darwin-arm64@4.20.0': 557 | optional: true 558 | 559 | '@rollup/rollup-darwin-x64@4.20.0': 560 | optional: true 561 | 562 | '@rollup/rollup-linux-arm-gnueabihf@4.20.0': 563 | optional: true 564 | 565 | '@rollup/rollup-linux-arm-musleabihf@4.20.0': 566 | optional: true 567 | 568 | '@rollup/rollup-linux-arm64-gnu@4.20.0': 569 | optional: true 570 | 571 | '@rollup/rollup-linux-arm64-musl@4.20.0': 572 | optional: true 573 | 574 | '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': 575 | optional: true 576 | 577 | '@rollup/rollup-linux-riscv64-gnu@4.20.0': 578 | optional: true 579 | 580 | '@rollup/rollup-linux-s390x-gnu@4.20.0': 581 | optional: true 582 | 583 | '@rollup/rollup-linux-x64-gnu@4.20.0': 584 | optional: true 585 | 586 | '@rollup/rollup-linux-x64-musl@4.20.0': 587 | optional: true 588 | 589 | '@rollup/rollup-win32-arm64-msvc@4.20.0': 590 | optional: true 591 | 592 | '@rollup/rollup-win32-ia32-msvc@4.20.0': 593 | optional: true 594 | 595 | '@rollup/rollup-win32-x64-msvc@4.20.0': 596 | optional: true 597 | 598 | '@swc/core-darwin-arm64@1.7.5': 599 | optional: true 600 | 601 | '@swc/core-darwin-x64@1.7.5': 602 | optional: true 603 | 604 | '@swc/core-linux-arm-gnueabihf@1.7.5': 605 | optional: true 606 | 607 | '@swc/core-linux-arm64-gnu@1.7.5': 608 | optional: true 609 | 610 | '@swc/core-linux-arm64-musl@1.7.5': 611 | optional: true 612 | 613 | '@swc/core-linux-x64-gnu@1.7.5': 614 | optional: true 615 | 616 | '@swc/core-linux-x64-musl@1.7.5': 617 | optional: true 618 | 619 | '@swc/core-win32-arm64-msvc@1.7.5': 620 | optional: true 621 | 622 | '@swc/core-win32-ia32-msvc@1.7.5': 623 | optional: true 624 | 625 | '@swc/core-win32-x64-msvc@1.7.5': 626 | optional: true 627 | 628 | '@swc/core@1.7.5': 629 | dependencies: 630 | '@swc/counter': 0.1.3 631 | '@swc/types': 0.1.12 632 | optionalDependencies: 633 | '@swc/core-darwin-arm64': 1.7.5 634 | '@swc/core-darwin-x64': 1.7.5 635 | '@swc/core-linux-arm-gnueabihf': 1.7.5 636 | '@swc/core-linux-arm64-gnu': 1.7.5 637 | '@swc/core-linux-arm64-musl': 1.7.5 638 | '@swc/core-linux-x64-gnu': 1.7.5 639 | '@swc/core-linux-x64-musl': 1.7.5 640 | '@swc/core-win32-arm64-msvc': 1.7.5 641 | '@swc/core-win32-ia32-msvc': 1.7.5 642 | '@swc/core-win32-x64-msvc': 1.7.5 643 | 644 | '@swc/counter@0.1.3': {} 645 | 646 | '@swc/types@0.1.12': 647 | dependencies: 648 | '@swc/counter': 0.1.3 649 | 650 | '@types/estree@1.0.5': {} 651 | 652 | '@types/node@22.1.0': 653 | dependencies: 654 | undici-types: 6.13.0 655 | 656 | '@types/prop-types@15.7.12': {} 657 | 658 | '@types/react-dom@18.3.0': 659 | dependencies: 660 | '@types/react': 18.3.3 661 | 662 | '@types/react@18.3.3': 663 | dependencies: 664 | '@types/prop-types': 15.7.12 665 | csstype: 3.1.3 666 | 667 | '@vitejs/plugin-react-swc@3.7.0(vite@5.3.5(@types/node@22.1.0))': 668 | dependencies: 669 | '@swc/core': 1.7.5 670 | vite: 5.3.5(@types/node@22.1.0) 671 | transitivePeerDependencies: 672 | - '@swc/helpers' 673 | 674 | csstype@3.1.3: {} 675 | 676 | esbuild@0.21.5: 677 | optionalDependencies: 678 | '@esbuild/aix-ppc64': 0.21.5 679 | '@esbuild/android-arm': 0.21.5 680 | '@esbuild/android-arm64': 0.21.5 681 | '@esbuild/android-x64': 0.21.5 682 | '@esbuild/darwin-arm64': 0.21.5 683 | '@esbuild/darwin-x64': 0.21.5 684 | '@esbuild/freebsd-arm64': 0.21.5 685 | '@esbuild/freebsd-x64': 0.21.5 686 | '@esbuild/linux-arm': 0.21.5 687 | '@esbuild/linux-arm64': 0.21.5 688 | '@esbuild/linux-ia32': 0.21.5 689 | '@esbuild/linux-loong64': 0.21.5 690 | '@esbuild/linux-mips64el': 0.21.5 691 | '@esbuild/linux-ppc64': 0.21.5 692 | '@esbuild/linux-riscv64': 0.21.5 693 | '@esbuild/linux-s390x': 0.21.5 694 | '@esbuild/linux-x64': 0.21.5 695 | '@esbuild/netbsd-x64': 0.21.5 696 | '@esbuild/openbsd-x64': 0.21.5 697 | '@esbuild/sunos-x64': 0.21.5 698 | '@esbuild/win32-arm64': 0.21.5 699 | '@esbuild/win32-ia32': 0.21.5 700 | '@esbuild/win32-x64': 0.21.5 701 | 702 | fsevents@2.3.3: 703 | optional: true 704 | 705 | js-tokens@4.0.0: {} 706 | 707 | loose-envify@1.4.0: 708 | dependencies: 709 | js-tokens: 4.0.0 710 | 711 | nanoid@3.3.7: {} 712 | 713 | picocolors@1.0.1: {} 714 | 715 | postcss@8.4.40: 716 | dependencies: 717 | nanoid: 3.3.7 718 | picocolors: 1.0.1 719 | source-map-js: 1.2.0 720 | 721 | react-dom@18.3.1(react@18.3.1): 722 | dependencies: 723 | loose-envify: 1.4.0 724 | react: 18.3.1 725 | scheduler: 0.23.2 726 | 727 | react-router-dom@6.26.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): 728 | dependencies: 729 | '@remix-run/router': 1.19.0 730 | react: 18.3.1 731 | react-dom: 18.3.1(react@18.3.1) 732 | react-router: 6.26.0(react@18.3.1) 733 | 734 | react-router@6.26.0(react@18.3.1): 735 | dependencies: 736 | '@remix-run/router': 1.19.0 737 | react: 18.3.1 738 | 739 | react@18.3.1: 740 | dependencies: 741 | loose-envify: 1.4.0 742 | 743 | rollup@4.20.0: 744 | dependencies: 745 | '@types/estree': 1.0.5 746 | optionalDependencies: 747 | '@rollup/rollup-android-arm-eabi': 4.20.0 748 | '@rollup/rollup-android-arm64': 4.20.0 749 | '@rollup/rollup-darwin-arm64': 4.20.0 750 | '@rollup/rollup-darwin-x64': 4.20.0 751 | '@rollup/rollup-linux-arm-gnueabihf': 4.20.0 752 | '@rollup/rollup-linux-arm-musleabihf': 4.20.0 753 | '@rollup/rollup-linux-arm64-gnu': 4.20.0 754 | '@rollup/rollup-linux-arm64-musl': 4.20.0 755 | '@rollup/rollup-linux-powerpc64le-gnu': 4.20.0 756 | '@rollup/rollup-linux-riscv64-gnu': 4.20.0 757 | '@rollup/rollup-linux-s390x-gnu': 4.20.0 758 | '@rollup/rollup-linux-x64-gnu': 4.20.0 759 | '@rollup/rollup-linux-x64-musl': 4.20.0 760 | '@rollup/rollup-win32-arm64-msvc': 4.20.0 761 | '@rollup/rollup-win32-ia32-msvc': 4.20.0 762 | '@rollup/rollup-win32-x64-msvc': 4.20.0 763 | fsevents: 2.3.3 764 | 765 | scheduler@0.23.2: 766 | dependencies: 767 | loose-envify: 1.4.0 768 | 769 | source-map-js@1.2.0: {} 770 | 771 | typescript@5.5.4: {} 772 | 773 | undici-types@6.13.0: {} 774 | 775 | vite@5.3.5(@types/node@22.1.0): 776 | dependencies: 777 | esbuild: 0.21.5 778 | postcss: 8.4.40 779 | rollup: 4.20.0 780 | optionalDependencies: 781 | '@types/node': 22.1.0 782 | fsevents: 2.3.3 783 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { RouterProvider, createBrowserRouter } from 'react-router-dom' 2 | import routes from 'route-views' 3 | 4 | const router = createBrowserRouter(routes) 5 | 6 | function App() { 7 | return ( 8 | 11 | ) 12 | } 13 | 14 | export default App 15 | -------------------------------------------------------------------------------- /example/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | 5 | ReactDOM.createRoot(document.getElementById('root')!).render( 6 | 7 | 8 | 9 | ) 10 | -------------------------------------------------------------------------------- /example/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | return ( 3 |
404 Not Found
4 | ) 5 | } -------------------------------------------------------------------------------- /example/src/pages/bar/[dynamic].jsx: -------------------------------------------------------------------------------- 1 | import { useParams } from 'react-router-dom' 2 | 3 | export function Component() { 4 | const { dynamic } = useParams() 5 | 6 | return
{dynamic}
7 | } 8 | 9 | if (import.meta.env.DEV) { 10 | Component.displayName = 'Dynamic' 11 | } 12 | -------------------------------------------------------------------------------- /example/src/pages/components/button.jsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | return 'button' 3 | } 4 | 5 | if (import.meta.env.DEV) { 6 | Component.displayName = 'Button' 7 | } 8 | -------------------------------------------------------------------------------- /example/src/pages/contact.jsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | return
contact
3 | } 4 | 5 | if (import.meta.env.DEV) { 6 | Component.displayName = 'Contact' 7 | } 8 | -------------------------------------------------------------------------------- /example/src/pages/error.tsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | throw new Error('route-error') 3 | } -------------------------------------------------------------------------------- /example/src/pages/foo/_type.jsx: -------------------------------------------------------------------------------- 1 | import { useParams } from 'react-router-dom' 2 | 3 | export function Component() { 4 | const { type } = useParams() 5 | 6 | return
{type}
7 | } 8 | 9 | if (import.meta.env.DEV) { 10 | Component.displayName = 'Type' 11 | } 12 | -------------------------------------------------------------------------------- /example/src/pages/foo/bar.jsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | return
bar
3 | } 4 | 5 | if (import.meta.env.DEV) { 6 | Component.displayName = 'Bar' 7 | } 8 | -------------------------------------------------------------------------------- /example/src/pages/foo/index.jsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | return
foo
3 | } 4 | 5 | if (import.meta.env.DEV) { 6 | Component.displayName = 'Foo' 7 | } 8 | -------------------------------------------------------------------------------- /example/src/pages/foo/layout.jsx: -------------------------------------------------------------------------------- 1 | import { Outlet } from 'react-router-dom' 2 | 3 | const el = document.createElement('div') 4 | el.id = 'foo_layout' 5 | document.body.appendChild(el) 6 | 7 | export function Component() { 8 | return ( 9 | <> 10 |
layout-foo
11 | 12 | 13 | ) 14 | } 15 | 16 | if (import.meta.env.DEV) { 17 | Component.displayName = 'FooLayout' 18 | } 19 | -------------------------------------------------------------------------------- /example/src/pages/hyphen-name.tsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | return
hyphen-name
3 | } 4 | 5 | if (import.meta.env.DEV) { 6 | Component.displayName = 'HyphenName' 7 | } 8 | -------------------------------------------------------------------------------- /example/src/pages/index.jsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | return
index
3 | } 4 | 5 | if (import.meta.env.DEV) { 6 | Component.displayName = 'Home' 7 | } 8 | -------------------------------------------------------------------------------- /example/src/pages/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Outlet, Link, useRouteLoaderData } from 'react-router-dom' 2 | 3 | export const id = '/' 4 | 5 | export function loader() { 6 | return { 7 | root: 'root' 8 | } 9 | } 10 | 11 | export function handle() {} 12 | 13 | export function action() {} 14 | 15 | export function ErrorBoundary() { 16 | return ( 17 |
Route Error
18 | ) 19 | } 20 | 21 | export function shouldRevalidate() { 22 | return false 23 | } 24 | 25 | export function Component() { 26 | const data = useRouteLoaderData('/') as { root: string } 27 | 28 | return ( 29 | <> 30 |
31 | index{' '} 32 | /contact{' '} 33 | /about{' '} 34 | /utils{' '} 35 | /foo{' '} 36 | /foo/bar{' '} 37 | /foo/:type{' '} 38 | /bar/:dynamic{' '} 39 | /hyphen-name{' '} 40 | /excluded/components 41 | /error 42 |
43 |
layout
44 |
{data.root}
45 | 46 | 47 | ) 48 | } 49 | 50 | if (import.meta.env.DEV) { 51 | Component.displayName = 'Layout' 52 | } 53 | -------------------------------------------------------------------------------- /example/src/pages/sync.tsx: -------------------------------------------------------------------------------- 1 | const el = document.createElement('div') 2 | el.id = 'sync' 3 | document.body.appendChild(el) 4 | 5 | export function Component() { 6 | return 'sync' 7 | } 8 | 9 | if (import.meta.env.DEV) { 10 | Component.displayName = 'SyncRoute' 11 | } 12 | -------------------------------------------------------------------------------- /example/src/pages/utils.tsx: -------------------------------------------------------------------------------- 1 | export function Component() { 2 | return 'utils' 3 | } 4 | 5 | if (import.meta.env.DEV) { 6 | Component.displayName = 'Utils' 7 | } 8 | -------------------------------------------------------------------------------- /example/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module 'route-views' { 4 | const routes: (import('react-router-dom').RouteObject)[]; 5 | 6 | export default routes; 7 | } 8 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /example/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /example/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react-swc' 3 | import router from 'vite-plugin-react-views' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react(), 9 | router({ 10 | exclude(path) { 11 | return path.includes('utils') || path.includes('components') 12 | }, 13 | sync(path) { 14 | return path.includes('sync') || path.includes('foo') || path.includes('hyphen-name') 15 | } 16 | }) 17 | ], 18 | }) 19 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import path from 'node:path' 3 | import { init, parse } from 'es-module-lexer' 4 | import { transformWithEsbuild, normalizePath } from 'vite' 5 | import type { PluginOption, ResolvedConfig, EsbuildTransformOptions } from 'vite' 6 | import type { RouteObject } from 'react-router-dom' 7 | 8 | interface Options { 9 | dir?: string; 10 | exclude?(path: string): boolean; 11 | sync?(path: string): boolean; 12 | extensions?: string[]; 13 | } 14 | 15 | function readContent(id: string) { 16 | return fs.readFileSync(id).toString().trim() 17 | } 18 | 19 | function join(...rest: string[]) { 20 | return normalizePath(path.join(...rest)) 21 | } 22 | 23 | function getComponentPrefix(path: string) { 24 | return path 25 | .slice(0) 26 | .split('/') 27 | .map(segment => segment 28 | .replace(/^([a-z])/, (_, $1) => $1.toUpperCase()) 29 | .replace(/[^a-zA-Z0-9_$]/g, '_') 30 | ) 31 | .join('') 32 | } 33 | 34 | function removeExt(file: string) { 35 | return file.slice(0, file.length - path.extname(file).length) 36 | } 37 | 38 | function toDynamic(segment: string) { 39 | return segment.replace(/^(?:_(.+)|\[(.+)\])$/, (_, $1, $2) => `:${$1 || $2}`) 40 | } 41 | 42 | const splitMark = '__' 43 | const routeArgs = ['Component', 'ErrorBoundary', 'loader', 'action', 'handle', 'shouldRevalidate', 'errorElement', 'id'] 44 | const re = new RegExp(`"(\\(\\) => import\\(.+\\))"|: "(.+${splitMark}(?:${routeArgs.join('|')}))"`, 'g') 45 | 46 | function VitePluginReactRouter(opts: Options = {}): PluginOption { 47 | const { 48 | dir = 'src/pages', 49 | exclude, 50 | sync, 51 | extensions = ['js', 'jsx', 'ts', 'tsx'] 52 | } = opts 53 | 54 | let _config: ResolvedConfig 55 | let originDirPath: string 56 | const ROUTE_RE = new RegExp(`\\.(${extensions.join('|')})$`) 57 | const MODULE_NAME = 'route-views' 58 | const VIRTUAL_MODULE = '\0' + MODULE_NAME + `.${extensions[1]}` 59 | const emptyFiles = new Set() 60 | const nonEmptyFiles = new Set() 61 | 62 | async function createRoutes() { 63 | originDirPath = join(_config.root, dir) 64 | let stackDirs = [originDirPath] 65 | let stackFiles: string[][] = [] 66 | let stackIndexs: number[] = [] 67 | 68 | let currentFiles = fs.readdirSync(originDirPath) 69 | let currentIndex = 0 70 | 71 | let workFile: string | undefined = currentFiles[currentIndex++] 72 | let workRoute: RouteObject = { path: '/', children: [] } 73 | let stackRoutes: RouteObject[] = [workRoute] 74 | 75 | let syncRoutesMap: Record> = {} 76 | 77 | async function parseRoute(code: string, id: string, routePath: string) { 78 | const result = await transformWithEsbuild(code, id, { 79 | loader: path.extname(id).slice(1) as EsbuildTransformOptions['loader'] 80 | }) 81 | 82 | let prefix = getComponentPrefix(removeExt(routePath)) 83 | const route: Record = {} 84 | 85 | try { 86 | await init 87 | const [, exports] = parse(result.code) 88 | for (const e of exports) { 89 | const key = e.n as keyof RouteObject 90 | if (routeArgs.includes(key)) { 91 | route[key] = prefix + splitMark + key 92 | } 93 | } 94 | } catch (error) { 95 | console.error(`[parse error]: `, error) 96 | } 97 | 98 | syncRoutesMap[id] = { ...route } 99 | return route 100 | } 101 | 102 | const getElement = async (id: string, code?: string, routePath?: string, sync?: boolean) => { 103 | if (sync) { 104 | return await parseRoute(code!, id, routePath!) 105 | } 106 | 107 | return { lazy: `() => import('${id}')` as any } 108 | } 109 | 110 | while (workFile != null) { 111 | const filePath = join(...stackDirs, workFile) 112 | const routePath = filePath.slice(originDirPath.length) 113 | const stat = fs.statSync(filePath) 114 | 115 | if (stat.isDirectory() && !exclude?.(routePath)) { 116 | const nextFiles = fs.readdirSync(filePath) 117 | 118 | if (nextFiles.length) { 119 | stackDirs.push(workFile) 120 | stackFiles.push(currentFiles) 121 | stackIndexs.push(currentIndex) 122 | 123 | const len: number = workRoute.children!.push({ path: workFile, children: [] }) 124 | stackRoutes.push(workRoute) 125 | 126 | workRoute = workRoute.children![len - 1]! 127 | currentIndex = 0 128 | currentFiles = nextFiles 129 | } 130 | } else if (ROUTE_RE.test(workFile) && !exclude?.(removeExt(routePath))) { 131 | const content = readContent(filePath) 132 | if (content) { 133 | nonEmptyFiles.add(filePath) 134 | const segment = removeExt(workFile) 135 | const isRoot = stackFiles.length === 0 136 | 137 | if (segment === 'layout') { 138 | Object.assign(workRoute, await getElement(filePath, content, routePath, isRoot)) 139 | } else { 140 | const route = await getElement(filePath, content, routePath, sync?.(routePath)) as RouteObject 141 | 142 | if (isRoot && segment === '404') { 143 | route.path = '*' 144 | stackRoutes.push(route) 145 | } else { 146 | if (segment === 'index') { 147 | route.index = true 148 | } else { 149 | route.path = toDynamic(segment) 150 | } 151 | 152 | workRoute.children?.push(route) 153 | } 154 | } 155 | } else { 156 | emptyFiles.add(filePath) 157 | } 158 | } 159 | 160 | while (currentIndex != null && currentFiles && currentIndex >= currentFiles.length) { 161 | currentFiles = stackFiles.pop()! 162 | currentIndex = stackIndexs.pop()! 163 | workRoute = stackRoutes.pop()! 164 | stackDirs.pop() 165 | } 166 | 167 | if (currentFiles && currentFiles.length) { 168 | workFile = currentFiles[currentIndex++] 169 | } else { 170 | workFile = undefined 171 | } 172 | } 173 | 174 | return { routes: stackRoutes.concat(workRoute), syncRoutesMap } 175 | } 176 | 177 | return { 178 | name: 'vite-plugin-react-views', 179 | enforce: 'post', 180 | configResolved(c) { 181 | _config = c 182 | }, 183 | configureServer(server) { 184 | function handleFileChange(path: string) { 185 | path = normalizePath(removeExt(path)) 186 | 187 | if (path.includes(dir) && !exclude?.(path.slice(originDirPath.length))) { 188 | const mod = server.moduleGraph.getModuleById(VIRTUAL_MODULE) 189 | if (mod) { 190 | server.moduleGraph.invalidateModule(mod) 191 | } 192 | 193 | server.ws.send({ type: 'full-reload' }) 194 | } 195 | } 196 | 197 | server.watcher.on('add', handleFileChange) 198 | server.watcher.on('unlink', handleFileChange) 199 | server.watcher.on('change', (path) => { 200 | path = normalizePath(path) 201 | const content = readContent(path) 202 | 203 | if (emptyFiles.has(path) && content) { 204 | emptyFiles.delete(path) 205 | nonEmptyFiles.add(path) 206 | handleFileChange(path) 207 | } else if (nonEmptyFiles.has(path) && !content) { 208 | emptyFiles.add(path) 209 | nonEmptyFiles.delete(path) 210 | handleFileChange(path) 211 | } 212 | }) 213 | }, 214 | resolveId(id: string) { 215 | if (id === MODULE_NAME) { 216 | return VIRTUAL_MODULE 217 | } 218 | }, 219 | async load(id) { 220 | if (id === VIRTUAL_MODULE) { 221 | const { routes, syncRoutesMap } = await createRoutes() 222 | 223 | return `${Object.keys(syncRoutesMap).map(id => { 224 | const route = syncRoutesMap[id] 225 | return `import { ${Object.keys(route).map(routeKey => `${routeKey} as ${route[routeKey]}`).join(', ')} } from '${id}'` 226 | }).join('\n')} 227 | 228 | export default ${JSON.stringify(routes, null, 2) 229 | .replace(re, (_, $1, $2) => $2 ? `: ${$2}` : $1)}` 230 | } 231 | }, 232 | } 233 | } 234 | 235 | export default VitePluginReactRouter 236 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-plugin-react-views", 3 | "version": "2.1.1", 4 | "description": "A vite plugin based on File System for creating routes automatically.", 5 | "main": "./dist/index.js", 6 | "type": "module", 7 | "types": "./dist/index.d.ts", 8 | "scripts": { 9 | "dev": "vite build --watch", 10 | "build": "vite build && tsc", 11 | "test": "pnpm test-serve && pnpm test-build", 12 | "test-serve": "vitest run", 13 | "test-build": "VITEST_BUILD=1 vitest run" 14 | }, 15 | "homepage": "https://github.com/KAROTT7/vite-plugin-react-views", 16 | "keywords": [ 17 | "vite", 18 | "vite-plugin", 19 | "react", 20 | "router", 21 | "react-router" 22 | ], 23 | "exports": { 24 | "import": "./dist/index.js", 25 | "require": "./dist/index.cjs", 26 | "types": "./dist/index.d.ts" 27 | }, 28 | "files": [ 29 | "dist" 30 | ], 31 | "author": "KAROTT7", 32 | "license": "MIT", 33 | "dependencies": { 34 | "es-module-lexer": "^1.2.1" 35 | }, 36 | "devDependencies": { 37 | "@types/node": "^22.1.0", 38 | "@types/react": "^18.0.28", 39 | "playwright-chromium": "^1.27.1", 40 | "react-router-dom": ">=6.9.0", 41 | "typescript": "^5.5.4", 42 | "vite": "^5.3.5", 43 | "vitest": "^2.0.5" 44 | }, 45 | "peerDependencies": { 46 | "react-router-dom": ">=6.9.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | es-module-lexer: 12 | specifier: ^1.2.1 13 | version: 1.5.4 14 | devDependencies: 15 | '@types/node': 16 | specifier: ^22.1.0 17 | version: 22.1.0 18 | '@types/react': 19 | specifier: ^18.0.28 20 | version: 18.3.3 21 | playwright-chromium: 22 | specifier: ^1.27.1 23 | version: 1.45.3 24 | react-router-dom: 25 | specifier: '>=6.9.0' 26 | version: 6.26.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 27 | typescript: 28 | specifier: ^5.5.4 29 | version: 5.5.4 30 | vite: 31 | specifier: ^5.3.5 32 | version: 5.3.5(@types/node@22.1.0) 33 | vitest: 34 | specifier: ^2.0.5 35 | version: 2.0.5(@types/node@22.1.0) 36 | 37 | packages: 38 | 39 | '@ampproject/remapping@2.3.0': 40 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 41 | engines: {node: '>=6.0.0'} 42 | 43 | '@esbuild/aix-ppc64@0.21.5': 44 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 45 | engines: {node: '>=12'} 46 | cpu: [ppc64] 47 | os: [aix] 48 | 49 | '@esbuild/android-arm64@0.21.5': 50 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 51 | engines: {node: '>=12'} 52 | cpu: [arm64] 53 | os: [android] 54 | 55 | '@esbuild/android-arm@0.21.5': 56 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 57 | engines: {node: '>=12'} 58 | cpu: [arm] 59 | os: [android] 60 | 61 | '@esbuild/android-x64@0.21.5': 62 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 63 | engines: {node: '>=12'} 64 | cpu: [x64] 65 | os: [android] 66 | 67 | '@esbuild/darwin-arm64@0.21.5': 68 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 69 | engines: {node: '>=12'} 70 | cpu: [arm64] 71 | os: [darwin] 72 | 73 | '@esbuild/darwin-x64@0.21.5': 74 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 75 | engines: {node: '>=12'} 76 | cpu: [x64] 77 | os: [darwin] 78 | 79 | '@esbuild/freebsd-arm64@0.21.5': 80 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 81 | engines: {node: '>=12'} 82 | cpu: [arm64] 83 | os: [freebsd] 84 | 85 | '@esbuild/freebsd-x64@0.21.5': 86 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 87 | engines: {node: '>=12'} 88 | cpu: [x64] 89 | os: [freebsd] 90 | 91 | '@esbuild/linux-arm64@0.21.5': 92 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 93 | engines: {node: '>=12'} 94 | cpu: [arm64] 95 | os: [linux] 96 | 97 | '@esbuild/linux-arm@0.21.5': 98 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 99 | engines: {node: '>=12'} 100 | cpu: [arm] 101 | os: [linux] 102 | 103 | '@esbuild/linux-ia32@0.21.5': 104 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 105 | engines: {node: '>=12'} 106 | cpu: [ia32] 107 | os: [linux] 108 | 109 | '@esbuild/linux-loong64@0.21.5': 110 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 111 | engines: {node: '>=12'} 112 | cpu: [loong64] 113 | os: [linux] 114 | 115 | '@esbuild/linux-mips64el@0.21.5': 116 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 117 | engines: {node: '>=12'} 118 | cpu: [mips64el] 119 | os: [linux] 120 | 121 | '@esbuild/linux-ppc64@0.21.5': 122 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 123 | engines: {node: '>=12'} 124 | cpu: [ppc64] 125 | os: [linux] 126 | 127 | '@esbuild/linux-riscv64@0.21.5': 128 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 129 | engines: {node: '>=12'} 130 | cpu: [riscv64] 131 | os: [linux] 132 | 133 | '@esbuild/linux-s390x@0.21.5': 134 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 135 | engines: {node: '>=12'} 136 | cpu: [s390x] 137 | os: [linux] 138 | 139 | '@esbuild/linux-x64@0.21.5': 140 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 141 | engines: {node: '>=12'} 142 | cpu: [x64] 143 | os: [linux] 144 | 145 | '@esbuild/netbsd-x64@0.21.5': 146 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 147 | engines: {node: '>=12'} 148 | cpu: [x64] 149 | os: [netbsd] 150 | 151 | '@esbuild/openbsd-x64@0.21.5': 152 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 153 | engines: {node: '>=12'} 154 | cpu: [x64] 155 | os: [openbsd] 156 | 157 | '@esbuild/sunos-x64@0.21.5': 158 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 159 | engines: {node: '>=12'} 160 | cpu: [x64] 161 | os: [sunos] 162 | 163 | '@esbuild/win32-arm64@0.21.5': 164 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 165 | engines: {node: '>=12'} 166 | cpu: [arm64] 167 | os: [win32] 168 | 169 | '@esbuild/win32-ia32@0.21.5': 170 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 171 | engines: {node: '>=12'} 172 | cpu: [ia32] 173 | os: [win32] 174 | 175 | '@esbuild/win32-x64@0.21.5': 176 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 177 | engines: {node: '>=12'} 178 | cpu: [x64] 179 | os: [win32] 180 | 181 | '@jridgewell/gen-mapping@0.3.5': 182 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} 183 | engines: {node: '>=6.0.0'} 184 | 185 | '@jridgewell/resolve-uri@3.1.2': 186 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 187 | engines: {node: '>=6.0.0'} 188 | 189 | '@jridgewell/set-array@1.2.1': 190 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 191 | engines: {node: '>=6.0.0'} 192 | 193 | '@jridgewell/sourcemap-codec@1.5.0': 194 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 195 | 196 | '@jridgewell/trace-mapping@0.3.25': 197 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 198 | 199 | '@remix-run/router@1.19.0': 200 | resolution: {integrity: sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==} 201 | engines: {node: '>=14.0.0'} 202 | 203 | '@rollup/rollup-android-arm-eabi@4.20.0': 204 | resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} 205 | cpu: [arm] 206 | os: [android] 207 | 208 | '@rollup/rollup-android-arm64@4.20.0': 209 | resolution: {integrity: sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==} 210 | cpu: [arm64] 211 | os: [android] 212 | 213 | '@rollup/rollup-darwin-arm64@4.20.0': 214 | resolution: {integrity: sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==} 215 | cpu: [arm64] 216 | os: [darwin] 217 | 218 | '@rollup/rollup-darwin-x64@4.20.0': 219 | resolution: {integrity: sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==} 220 | cpu: [x64] 221 | os: [darwin] 222 | 223 | '@rollup/rollup-linux-arm-gnueabihf@4.20.0': 224 | resolution: {integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==} 225 | cpu: [arm] 226 | os: [linux] 227 | libc: [glibc] 228 | 229 | '@rollup/rollup-linux-arm-musleabihf@4.20.0': 230 | resolution: {integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==} 231 | cpu: [arm] 232 | os: [linux] 233 | libc: [musl] 234 | 235 | '@rollup/rollup-linux-arm64-gnu@4.20.0': 236 | resolution: {integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==} 237 | cpu: [arm64] 238 | os: [linux] 239 | libc: [glibc] 240 | 241 | '@rollup/rollup-linux-arm64-musl@4.20.0': 242 | resolution: {integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==} 243 | cpu: [arm64] 244 | os: [linux] 245 | libc: [musl] 246 | 247 | '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': 248 | resolution: {integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==} 249 | cpu: [ppc64] 250 | os: [linux] 251 | libc: [glibc] 252 | 253 | '@rollup/rollup-linux-riscv64-gnu@4.20.0': 254 | resolution: {integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==} 255 | cpu: [riscv64] 256 | os: [linux] 257 | libc: [glibc] 258 | 259 | '@rollup/rollup-linux-s390x-gnu@4.20.0': 260 | resolution: {integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==} 261 | cpu: [s390x] 262 | os: [linux] 263 | libc: [glibc] 264 | 265 | '@rollup/rollup-linux-x64-gnu@4.20.0': 266 | resolution: {integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==} 267 | cpu: [x64] 268 | os: [linux] 269 | libc: [glibc] 270 | 271 | '@rollup/rollup-linux-x64-musl@4.20.0': 272 | resolution: {integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==} 273 | cpu: [x64] 274 | os: [linux] 275 | libc: [musl] 276 | 277 | '@rollup/rollup-win32-arm64-msvc@4.20.0': 278 | resolution: {integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==} 279 | cpu: [arm64] 280 | os: [win32] 281 | 282 | '@rollup/rollup-win32-ia32-msvc@4.20.0': 283 | resolution: {integrity: sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==} 284 | cpu: [ia32] 285 | os: [win32] 286 | 287 | '@rollup/rollup-win32-x64-msvc@4.20.0': 288 | resolution: {integrity: sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==} 289 | cpu: [x64] 290 | os: [win32] 291 | 292 | '@types/estree@1.0.5': 293 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 294 | 295 | '@types/node@22.1.0': 296 | resolution: {integrity: sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==} 297 | 298 | '@types/prop-types@15.7.12': 299 | resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} 300 | 301 | '@types/react@18.3.3': 302 | resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} 303 | 304 | '@vitest/expect@2.0.5': 305 | resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} 306 | 307 | '@vitest/pretty-format@2.0.5': 308 | resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==} 309 | 310 | '@vitest/runner@2.0.5': 311 | resolution: {integrity: sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==} 312 | 313 | '@vitest/snapshot@2.0.5': 314 | resolution: {integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==} 315 | 316 | '@vitest/spy@2.0.5': 317 | resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} 318 | 319 | '@vitest/utils@2.0.5': 320 | resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} 321 | 322 | assertion-error@2.0.1: 323 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 324 | engines: {node: '>=12'} 325 | 326 | cac@6.7.14: 327 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 328 | engines: {node: '>=8'} 329 | 330 | chai@5.1.1: 331 | resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} 332 | engines: {node: '>=12'} 333 | 334 | check-error@2.1.1: 335 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} 336 | engines: {node: '>= 16'} 337 | 338 | cross-spawn@7.0.3: 339 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 340 | engines: {node: '>= 8'} 341 | 342 | csstype@3.1.3: 343 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 344 | 345 | debug@4.3.6: 346 | resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} 347 | engines: {node: '>=6.0'} 348 | peerDependencies: 349 | supports-color: '*' 350 | peerDependenciesMeta: 351 | supports-color: 352 | optional: true 353 | 354 | deep-eql@5.0.2: 355 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} 356 | engines: {node: '>=6'} 357 | 358 | es-module-lexer@1.5.4: 359 | resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} 360 | 361 | esbuild@0.21.5: 362 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 363 | engines: {node: '>=12'} 364 | hasBin: true 365 | 366 | estree-walker@3.0.3: 367 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 368 | 369 | execa@8.0.1: 370 | resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} 371 | engines: {node: '>=16.17'} 372 | 373 | fsevents@2.3.3: 374 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 375 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 376 | os: [darwin] 377 | 378 | get-func-name@2.0.2: 379 | resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} 380 | 381 | get-stream@8.0.1: 382 | resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} 383 | engines: {node: '>=16'} 384 | 385 | human-signals@5.0.0: 386 | resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} 387 | engines: {node: '>=16.17.0'} 388 | 389 | is-stream@3.0.0: 390 | resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} 391 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 392 | 393 | isexe@2.0.0: 394 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 395 | 396 | js-tokens@4.0.0: 397 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 398 | 399 | loose-envify@1.4.0: 400 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 401 | hasBin: true 402 | 403 | loupe@3.1.1: 404 | resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==} 405 | 406 | magic-string@0.30.11: 407 | resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} 408 | 409 | merge-stream@2.0.0: 410 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 411 | 412 | mimic-fn@4.0.0: 413 | resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} 414 | engines: {node: '>=12'} 415 | 416 | ms@2.1.2: 417 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 418 | 419 | nanoid@3.3.7: 420 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 421 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 422 | hasBin: true 423 | 424 | npm-run-path@5.3.0: 425 | resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} 426 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 427 | 428 | onetime@6.0.0: 429 | resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} 430 | engines: {node: '>=12'} 431 | 432 | path-key@3.1.1: 433 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 434 | engines: {node: '>=8'} 435 | 436 | path-key@4.0.0: 437 | resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} 438 | engines: {node: '>=12'} 439 | 440 | pathe@1.1.2: 441 | resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} 442 | 443 | pathval@2.0.0: 444 | resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} 445 | engines: {node: '>= 14.16'} 446 | 447 | picocolors@1.0.1: 448 | resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} 449 | 450 | playwright-chromium@1.45.3: 451 | resolution: {integrity: sha512-GXY/+1HScU5soR06lu8sc7cnXWBnfWDGH2JV+D3wqxApb9qJbSxDK40H8loOok+naxMO7x6yhgPHwpRSCV9dug==} 452 | engines: {node: '>=18'} 453 | hasBin: true 454 | 455 | playwright-core@1.45.3: 456 | resolution: {integrity: sha512-+ym0jNbcjikaOwwSZycFbwkWgfruWvYlJfThKYAlImbxUgdWFO2oW70ojPm4OpE4t6TAo2FY/smM+hpVTtkhDA==} 457 | engines: {node: '>=18'} 458 | hasBin: true 459 | 460 | postcss@8.4.40: 461 | resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} 462 | engines: {node: ^10 || ^12 || >=14} 463 | 464 | react-dom@18.3.1: 465 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} 466 | peerDependencies: 467 | react: ^18.3.1 468 | 469 | react-router-dom@6.26.0: 470 | resolution: {integrity: sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ==} 471 | engines: {node: '>=14.0.0'} 472 | peerDependencies: 473 | react: '>=16.8' 474 | react-dom: '>=16.8' 475 | 476 | react-router@6.26.0: 477 | resolution: {integrity: sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==} 478 | engines: {node: '>=14.0.0'} 479 | peerDependencies: 480 | react: '>=16.8' 481 | 482 | react@18.3.1: 483 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} 484 | engines: {node: '>=0.10.0'} 485 | 486 | rollup@4.20.0: 487 | resolution: {integrity: sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==} 488 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 489 | hasBin: true 490 | 491 | scheduler@0.23.2: 492 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} 493 | 494 | shebang-command@2.0.0: 495 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 496 | engines: {node: '>=8'} 497 | 498 | shebang-regex@3.0.0: 499 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 500 | engines: {node: '>=8'} 501 | 502 | siginfo@2.0.0: 503 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 504 | 505 | signal-exit@4.1.0: 506 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 507 | engines: {node: '>=14'} 508 | 509 | source-map-js@1.2.0: 510 | resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} 511 | engines: {node: '>=0.10.0'} 512 | 513 | stackback@0.0.2: 514 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 515 | 516 | std-env@3.7.0: 517 | resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} 518 | 519 | strip-final-newline@3.0.0: 520 | resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} 521 | engines: {node: '>=12'} 522 | 523 | tinybench@2.9.0: 524 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 525 | 526 | tinypool@1.0.0: 527 | resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==} 528 | engines: {node: ^18.0.0 || >=20.0.0} 529 | 530 | tinyrainbow@1.2.0: 531 | resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} 532 | engines: {node: '>=14.0.0'} 533 | 534 | tinyspy@3.0.0: 535 | resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==} 536 | engines: {node: '>=14.0.0'} 537 | 538 | typescript@5.5.4: 539 | resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} 540 | engines: {node: '>=14.17'} 541 | hasBin: true 542 | 543 | undici-types@6.13.0: 544 | resolution: {integrity: sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==} 545 | 546 | vite-node@2.0.5: 547 | resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==} 548 | engines: {node: ^18.0.0 || >=20.0.0} 549 | hasBin: true 550 | 551 | vite@5.3.5: 552 | resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==} 553 | engines: {node: ^18.0.0 || >=20.0.0} 554 | hasBin: true 555 | peerDependencies: 556 | '@types/node': ^18.0.0 || >=20.0.0 557 | less: '*' 558 | lightningcss: ^1.21.0 559 | sass: '*' 560 | stylus: '*' 561 | sugarss: '*' 562 | terser: ^5.4.0 563 | peerDependenciesMeta: 564 | '@types/node': 565 | optional: true 566 | less: 567 | optional: true 568 | lightningcss: 569 | optional: true 570 | sass: 571 | optional: true 572 | stylus: 573 | optional: true 574 | sugarss: 575 | optional: true 576 | terser: 577 | optional: true 578 | 579 | vitest@2.0.5: 580 | resolution: {integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==} 581 | engines: {node: ^18.0.0 || >=20.0.0} 582 | hasBin: true 583 | peerDependencies: 584 | '@edge-runtime/vm': '*' 585 | '@types/node': ^18.0.0 || >=20.0.0 586 | '@vitest/browser': 2.0.5 587 | '@vitest/ui': 2.0.5 588 | happy-dom: '*' 589 | jsdom: '*' 590 | peerDependenciesMeta: 591 | '@edge-runtime/vm': 592 | optional: true 593 | '@types/node': 594 | optional: true 595 | '@vitest/browser': 596 | optional: true 597 | '@vitest/ui': 598 | optional: true 599 | happy-dom: 600 | optional: true 601 | jsdom: 602 | optional: true 603 | 604 | which@2.0.2: 605 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 606 | engines: {node: '>= 8'} 607 | hasBin: true 608 | 609 | why-is-node-running@2.3.0: 610 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 611 | engines: {node: '>=8'} 612 | hasBin: true 613 | 614 | snapshots: 615 | 616 | '@ampproject/remapping@2.3.0': 617 | dependencies: 618 | '@jridgewell/gen-mapping': 0.3.5 619 | '@jridgewell/trace-mapping': 0.3.25 620 | 621 | '@esbuild/aix-ppc64@0.21.5': 622 | optional: true 623 | 624 | '@esbuild/android-arm64@0.21.5': 625 | optional: true 626 | 627 | '@esbuild/android-arm@0.21.5': 628 | optional: true 629 | 630 | '@esbuild/android-x64@0.21.5': 631 | optional: true 632 | 633 | '@esbuild/darwin-arm64@0.21.5': 634 | optional: true 635 | 636 | '@esbuild/darwin-x64@0.21.5': 637 | optional: true 638 | 639 | '@esbuild/freebsd-arm64@0.21.5': 640 | optional: true 641 | 642 | '@esbuild/freebsd-x64@0.21.5': 643 | optional: true 644 | 645 | '@esbuild/linux-arm64@0.21.5': 646 | optional: true 647 | 648 | '@esbuild/linux-arm@0.21.5': 649 | optional: true 650 | 651 | '@esbuild/linux-ia32@0.21.5': 652 | optional: true 653 | 654 | '@esbuild/linux-loong64@0.21.5': 655 | optional: true 656 | 657 | '@esbuild/linux-mips64el@0.21.5': 658 | optional: true 659 | 660 | '@esbuild/linux-ppc64@0.21.5': 661 | optional: true 662 | 663 | '@esbuild/linux-riscv64@0.21.5': 664 | optional: true 665 | 666 | '@esbuild/linux-s390x@0.21.5': 667 | optional: true 668 | 669 | '@esbuild/linux-x64@0.21.5': 670 | optional: true 671 | 672 | '@esbuild/netbsd-x64@0.21.5': 673 | optional: true 674 | 675 | '@esbuild/openbsd-x64@0.21.5': 676 | optional: true 677 | 678 | '@esbuild/sunos-x64@0.21.5': 679 | optional: true 680 | 681 | '@esbuild/win32-arm64@0.21.5': 682 | optional: true 683 | 684 | '@esbuild/win32-ia32@0.21.5': 685 | optional: true 686 | 687 | '@esbuild/win32-x64@0.21.5': 688 | optional: true 689 | 690 | '@jridgewell/gen-mapping@0.3.5': 691 | dependencies: 692 | '@jridgewell/set-array': 1.2.1 693 | '@jridgewell/sourcemap-codec': 1.5.0 694 | '@jridgewell/trace-mapping': 0.3.25 695 | 696 | '@jridgewell/resolve-uri@3.1.2': {} 697 | 698 | '@jridgewell/set-array@1.2.1': {} 699 | 700 | '@jridgewell/sourcemap-codec@1.5.0': {} 701 | 702 | '@jridgewell/trace-mapping@0.3.25': 703 | dependencies: 704 | '@jridgewell/resolve-uri': 3.1.2 705 | '@jridgewell/sourcemap-codec': 1.5.0 706 | 707 | '@remix-run/router@1.19.0': {} 708 | 709 | '@rollup/rollup-android-arm-eabi@4.20.0': 710 | optional: true 711 | 712 | '@rollup/rollup-android-arm64@4.20.0': 713 | optional: true 714 | 715 | '@rollup/rollup-darwin-arm64@4.20.0': 716 | optional: true 717 | 718 | '@rollup/rollup-darwin-x64@4.20.0': 719 | optional: true 720 | 721 | '@rollup/rollup-linux-arm-gnueabihf@4.20.0': 722 | optional: true 723 | 724 | '@rollup/rollup-linux-arm-musleabihf@4.20.0': 725 | optional: true 726 | 727 | '@rollup/rollup-linux-arm64-gnu@4.20.0': 728 | optional: true 729 | 730 | '@rollup/rollup-linux-arm64-musl@4.20.0': 731 | optional: true 732 | 733 | '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': 734 | optional: true 735 | 736 | '@rollup/rollup-linux-riscv64-gnu@4.20.0': 737 | optional: true 738 | 739 | '@rollup/rollup-linux-s390x-gnu@4.20.0': 740 | optional: true 741 | 742 | '@rollup/rollup-linux-x64-gnu@4.20.0': 743 | optional: true 744 | 745 | '@rollup/rollup-linux-x64-musl@4.20.0': 746 | optional: true 747 | 748 | '@rollup/rollup-win32-arm64-msvc@4.20.0': 749 | optional: true 750 | 751 | '@rollup/rollup-win32-ia32-msvc@4.20.0': 752 | optional: true 753 | 754 | '@rollup/rollup-win32-x64-msvc@4.20.0': 755 | optional: true 756 | 757 | '@types/estree@1.0.5': {} 758 | 759 | '@types/node@22.1.0': 760 | dependencies: 761 | undici-types: 6.13.0 762 | 763 | '@types/prop-types@15.7.12': {} 764 | 765 | '@types/react@18.3.3': 766 | dependencies: 767 | '@types/prop-types': 15.7.12 768 | csstype: 3.1.3 769 | 770 | '@vitest/expect@2.0.5': 771 | dependencies: 772 | '@vitest/spy': 2.0.5 773 | '@vitest/utils': 2.0.5 774 | chai: 5.1.1 775 | tinyrainbow: 1.2.0 776 | 777 | '@vitest/pretty-format@2.0.5': 778 | dependencies: 779 | tinyrainbow: 1.2.0 780 | 781 | '@vitest/runner@2.0.5': 782 | dependencies: 783 | '@vitest/utils': 2.0.5 784 | pathe: 1.1.2 785 | 786 | '@vitest/snapshot@2.0.5': 787 | dependencies: 788 | '@vitest/pretty-format': 2.0.5 789 | magic-string: 0.30.11 790 | pathe: 1.1.2 791 | 792 | '@vitest/spy@2.0.5': 793 | dependencies: 794 | tinyspy: 3.0.0 795 | 796 | '@vitest/utils@2.0.5': 797 | dependencies: 798 | '@vitest/pretty-format': 2.0.5 799 | estree-walker: 3.0.3 800 | loupe: 3.1.1 801 | tinyrainbow: 1.2.0 802 | 803 | assertion-error@2.0.1: {} 804 | 805 | cac@6.7.14: {} 806 | 807 | chai@5.1.1: 808 | dependencies: 809 | assertion-error: 2.0.1 810 | check-error: 2.1.1 811 | deep-eql: 5.0.2 812 | loupe: 3.1.1 813 | pathval: 2.0.0 814 | 815 | check-error@2.1.1: {} 816 | 817 | cross-spawn@7.0.3: 818 | dependencies: 819 | path-key: 3.1.1 820 | shebang-command: 2.0.0 821 | which: 2.0.2 822 | 823 | csstype@3.1.3: {} 824 | 825 | debug@4.3.6: 826 | dependencies: 827 | ms: 2.1.2 828 | 829 | deep-eql@5.0.2: {} 830 | 831 | es-module-lexer@1.5.4: {} 832 | 833 | esbuild@0.21.5: 834 | optionalDependencies: 835 | '@esbuild/aix-ppc64': 0.21.5 836 | '@esbuild/android-arm': 0.21.5 837 | '@esbuild/android-arm64': 0.21.5 838 | '@esbuild/android-x64': 0.21.5 839 | '@esbuild/darwin-arm64': 0.21.5 840 | '@esbuild/darwin-x64': 0.21.5 841 | '@esbuild/freebsd-arm64': 0.21.5 842 | '@esbuild/freebsd-x64': 0.21.5 843 | '@esbuild/linux-arm': 0.21.5 844 | '@esbuild/linux-arm64': 0.21.5 845 | '@esbuild/linux-ia32': 0.21.5 846 | '@esbuild/linux-loong64': 0.21.5 847 | '@esbuild/linux-mips64el': 0.21.5 848 | '@esbuild/linux-ppc64': 0.21.5 849 | '@esbuild/linux-riscv64': 0.21.5 850 | '@esbuild/linux-s390x': 0.21.5 851 | '@esbuild/linux-x64': 0.21.5 852 | '@esbuild/netbsd-x64': 0.21.5 853 | '@esbuild/openbsd-x64': 0.21.5 854 | '@esbuild/sunos-x64': 0.21.5 855 | '@esbuild/win32-arm64': 0.21.5 856 | '@esbuild/win32-ia32': 0.21.5 857 | '@esbuild/win32-x64': 0.21.5 858 | 859 | estree-walker@3.0.3: 860 | dependencies: 861 | '@types/estree': 1.0.5 862 | 863 | execa@8.0.1: 864 | dependencies: 865 | cross-spawn: 7.0.3 866 | get-stream: 8.0.1 867 | human-signals: 5.0.0 868 | is-stream: 3.0.0 869 | merge-stream: 2.0.0 870 | npm-run-path: 5.3.0 871 | onetime: 6.0.0 872 | signal-exit: 4.1.0 873 | strip-final-newline: 3.0.0 874 | 875 | fsevents@2.3.3: 876 | optional: true 877 | 878 | get-func-name@2.0.2: {} 879 | 880 | get-stream@8.0.1: {} 881 | 882 | human-signals@5.0.0: {} 883 | 884 | is-stream@3.0.0: {} 885 | 886 | isexe@2.0.0: {} 887 | 888 | js-tokens@4.0.0: {} 889 | 890 | loose-envify@1.4.0: 891 | dependencies: 892 | js-tokens: 4.0.0 893 | 894 | loupe@3.1.1: 895 | dependencies: 896 | get-func-name: 2.0.2 897 | 898 | magic-string@0.30.11: 899 | dependencies: 900 | '@jridgewell/sourcemap-codec': 1.5.0 901 | 902 | merge-stream@2.0.0: {} 903 | 904 | mimic-fn@4.0.0: {} 905 | 906 | ms@2.1.2: {} 907 | 908 | nanoid@3.3.7: {} 909 | 910 | npm-run-path@5.3.0: 911 | dependencies: 912 | path-key: 4.0.0 913 | 914 | onetime@6.0.0: 915 | dependencies: 916 | mimic-fn: 4.0.0 917 | 918 | path-key@3.1.1: {} 919 | 920 | path-key@4.0.0: {} 921 | 922 | pathe@1.1.2: {} 923 | 924 | pathval@2.0.0: {} 925 | 926 | picocolors@1.0.1: {} 927 | 928 | playwright-chromium@1.45.3: 929 | dependencies: 930 | playwright-core: 1.45.3 931 | 932 | playwright-core@1.45.3: {} 933 | 934 | postcss@8.4.40: 935 | dependencies: 936 | nanoid: 3.3.7 937 | picocolors: 1.0.1 938 | source-map-js: 1.2.0 939 | 940 | react-dom@18.3.1(react@18.3.1): 941 | dependencies: 942 | loose-envify: 1.4.0 943 | react: 18.3.1 944 | scheduler: 0.23.2 945 | 946 | react-router-dom@6.26.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): 947 | dependencies: 948 | '@remix-run/router': 1.19.0 949 | react: 18.3.1 950 | react-dom: 18.3.1(react@18.3.1) 951 | react-router: 6.26.0(react@18.3.1) 952 | 953 | react-router@6.26.0(react@18.3.1): 954 | dependencies: 955 | '@remix-run/router': 1.19.0 956 | react: 18.3.1 957 | 958 | react@18.3.1: 959 | dependencies: 960 | loose-envify: 1.4.0 961 | 962 | rollup@4.20.0: 963 | dependencies: 964 | '@types/estree': 1.0.5 965 | optionalDependencies: 966 | '@rollup/rollup-android-arm-eabi': 4.20.0 967 | '@rollup/rollup-android-arm64': 4.20.0 968 | '@rollup/rollup-darwin-arm64': 4.20.0 969 | '@rollup/rollup-darwin-x64': 4.20.0 970 | '@rollup/rollup-linux-arm-gnueabihf': 4.20.0 971 | '@rollup/rollup-linux-arm-musleabihf': 4.20.0 972 | '@rollup/rollup-linux-arm64-gnu': 4.20.0 973 | '@rollup/rollup-linux-arm64-musl': 4.20.0 974 | '@rollup/rollup-linux-powerpc64le-gnu': 4.20.0 975 | '@rollup/rollup-linux-riscv64-gnu': 4.20.0 976 | '@rollup/rollup-linux-s390x-gnu': 4.20.0 977 | '@rollup/rollup-linux-x64-gnu': 4.20.0 978 | '@rollup/rollup-linux-x64-musl': 4.20.0 979 | '@rollup/rollup-win32-arm64-msvc': 4.20.0 980 | '@rollup/rollup-win32-ia32-msvc': 4.20.0 981 | '@rollup/rollup-win32-x64-msvc': 4.20.0 982 | fsevents: 2.3.3 983 | 984 | scheduler@0.23.2: 985 | dependencies: 986 | loose-envify: 1.4.0 987 | 988 | shebang-command@2.0.0: 989 | dependencies: 990 | shebang-regex: 3.0.0 991 | 992 | shebang-regex@3.0.0: {} 993 | 994 | siginfo@2.0.0: {} 995 | 996 | signal-exit@4.1.0: {} 997 | 998 | source-map-js@1.2.0: {} 999 | 1000 | stackback@0.0.2: {} 1001 | 1002 | std-env@3.7.0: {} 1003 | 1004 | strip-final-newline@3.0.0: {} 1005 | 1006 | tinybench@2.9.0: {} 1007 | 1008 | tinypool@1.0.0: {} 1009 | 1010 | tinyrainbow@1.2.0: {} 1011 | 1012 | tinyspy@3.0.0: {} 1013 | 1014 | typescript@5.5.4: {} 1015 | 1016 | undici-types@6.13.0: {} 1017 | 1018 | vite-node@2.0.5(@types/node@22.1.0): 1019 | dependencies: 1020 | cac: 6.7.14 1021 | debug: 4.3.6 1022 | pathe: 1.1.2 1023 | tinyrainbow: 1.2.0 1024 | vite: 5.3.5(@types/node@22.1.0) 1025 | transitivePeerDependencies: 1026 | - '@types/node' 1027 | - less 1028 | - lightningcss 1029 | - sass 1030 | - stylus 1031 | - sugarss 1032 | - supports-color 1033 | - terser 1034 | 1035 | vite@5.3.5(@types/node@22.1.0): 1036 | dependencies: 1037 | esbuild: 0.21.5 1038 | postcss: 8.4.40 1039 | rollup: 4.20.0 1040 | optionalDependencies: 1041 | '@types/node': 22.1.0 1042 | fsevents: 2.3.3 1043 | 1044 | vitest@2.0.5(@types/node@22.1.0): 1045 | dependencies: 1046 | '@ampproject/remapping': 2.3.0 1047 | '@vitest/expect': 2.0.5 1048 | '@vitest/pretty-format': 2.0.5 1049 | '@vitest/runner': 2.0.5 1050 | '@vitest/snapshot': 2.0.5 1051 | '@vitest/spy': 2.0.5 1052 | '@vitest/utils': 2.0.5 1053 | chai: 5.1.1 1054 | debug: 4.3.6 1055 | execa: 8.0.1 1056 | magic-string: 0.30.11 1057 | pathe: 1.1.2 1058 | std-env: 3.7.0 1059 | tinybench: 2.9.0 1060 | tinypool: 1.0.0 1061 | tinyrainbow: 1.2.0 1062 | vite: 5.3.5(@types/node@22.1.0) 1063 | vite-node: 2.0.5(@types/node@22.1.0) 1064 | why-is-node-running: 2.3.0 1065 | optionalDependencies: 1066 | '@types/node': 22.1.0 1067 | transitivePeerDependencies: 1068 | - less 1069 | - lightningcss 1070 | - sass 1071 | - stylus 1072 | - sugarss 1073 | - supports-color 1074 | - terser 1075 | 1076 | which@2.0.2: 1077 | dependencies: 1078 | isexe: 2.0.0 1079 | 1080 | why-is-node-running@2.3.0: 1081 | dependencies: 1082 | siginfo: 2.0.0 1083 | stackback: 0.0.2 1084 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "declarationDir": "dist", 5 | "emitDeclarationOnly": true, 6 | "strict": true, 7 | "module": "NodeNext", 8 | "skipLibCheck": true 9 | }, 10 | "include": ["index.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | 3 | export default defineConfig({ 4 | build: { 5 | outDir: 'dist', 6 | minify: false, 7 | lib: { 8 | entry: './index.ts', 9 | formats: ['es', 'cjs'], 10 | fileName: 'index' 11 | }, 12 | rollupOptions: { 13 | external: ['node:path', 'node:fs', 'vite'] 14 | } 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | setupFiles: ['./__tests__/setup.ts'], 6 | include: ['./__tests__/*.spec.ts'] 7 | } 8 | }) 9 | --------------------------------------------------------------------------------