├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── LICENSE.md ├── README.md ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── src ├── app.d.ts ├── app.html ├── lib │ ├── db.ts │ ├── identifier-handlers │ │ └── hyphen-identifier-handler.ts │ ├── index.ts │ ├── route-comparators │ │ └── named-comparator.ts │ ├── selfheal.ts │ ├── slug-sanitizers │ │ └── kebab-slug-sanitizer.ts │ └── types │ │ └── index.ts ├── routes │ ├── +page.svelte │ ├── +page.ts │ └── [id] │ │ ├── +error.svelte │ │ ├── +page.server.ts │ │ ├── +page.svelte │ │ └── details │ │ ├── +page.svelte │ │ └── [innerId] │ │ ├── +page.server.ts │ │ └── +page.svelte └── tests │ ├── identifier-handlers │ └── hyphen-identifier-handler.test.ts │ ├── route-comparators │ └── named-comparator.test.ts │ ├── slug-sanitizers │ └── kebab-slug-sanitizer.test.ts │ └── usage.test.ts ├── static ├── favicon.png └── svelte-selfheal.gif ├── svelte.config.js ├── tsconfig.json └── vite.config.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type { import("eslint").Linter.FlatConfig } */ 2 | module.exports = { 3 | root: true, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:svelte/recommended', 8 | 'prettier' 9 | ], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['@typescript-eslint'], 12 | parserOptions: { 13 | sourceType: 'module', 14 | ecmaVersion: 2020, 15 | extraFileExtensions: ['.svelte'] 16 | }, 17 | env: { 18 | browser: true, 19 | es2017: true, 20 | node: true 21 | }, 22 | overrides: [ 23 | { 24 | files: ['*.svelte'], 25 | parser: 'svelte-eslint-parser', 26 | parserOptions: { 27 | parser: '@typescript-eslint/parser' 28 | } 29 | } 30 | ] 31 | }; 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /dist 5 | /.svelte-kit 6 | /package 7 | .env 8 | .env.* 9 | !.env.example 10 | vite.config.js.timestamp-* 11 | vite.config.ts.timestamp-* 12 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Dominic Schmid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # svelte-selfheal 2 | 3 | A simple Svelte package inspired by [this video from Aaron Francis](https://www.youtube.com/watch?v=a6lnfyES-LA) and heavily based on [a similar package for Laravel](https://github.com/lukeraymonddowning/self-healing-urls). 4 | 5 | It allows you to redirect users to a canonical and SEO-friendly URL for a page, even if the slug is altered at any point or doesn't exist at all. 6 | 7 | ![svelte-selfheal-gif](./static/svelte-selfheal.gif) 8 | 9 | ### Example 10 | 11 | Canonical URL: `https://my-app.com/blog/my-fancy-title-5312` 12 | 13 | The following URLs would still redirect to the correct page 14 | 15 | - `/blog/my-fancy-title-5312` _(original)_ 16 | - `/blog/my-fancy-but-spelled-wrong-title-5312` 17 | - `/blog/5312` 18 | - `/blog/-5312` 19 | - `/blog/THIS should NOT be r3alURL -5312` 20 | 21 | ## Installation 22 | 23 | Install this package using any of the popular package managers. 24 | 25 | ``` 26 | npm i svelte-selfheal 27 | ``` 28 | 29 | ``` 30 | pnpm add svelte-selfheal 31 | ``` 32 | 33 | ``` 34 | yarn add svelte-selfheal 35 | ``` 36 | 37 | ## Usage 38 | 39 | Once installed, export a healer: 40 | 41 | ```ts 42 | import { selfheal } from 'svelte-selfheal'; 43 | 44 | export const healer = selfheal(); 45 | ``` 46 | 47 | Now you can use the self-healing functions anywhere across your app. 48 | 49 | ### Example +page.server.ts 50 | 51 | Inside your load function you want to 52 | 53 | 1. Separate the identifier from the slug using the handler you defined on creation 54 | 55 | ```ts 56 | const identifier = healer.parseId(params.id); 57 | ``` 58 | 59 | 2. Query the database using the ID and see if something is found 60 | 61 | ```ts 62 | const article = db.articles.find((article) => String(article.id) === identifier); 63 | if (!article) throw error(404, `Article "${identifier}" not found`); 64 | ``` 65 | 66 | 1. Create the slug using the DB values and compare it to the actual URL, then redirect if needed 67 | 68 | ```ts 69 | const expectedUrl = healer.createUrl(article.id, article.title, url.searchParams); 70 | const valid = healer.validate(expectedUrl, params.id, url.searchParams); 71 | if (!valid) throw redirect(301, expectedUrl); 72 | ``` 73 | 74 | Now you are guaranteed to either be on the `404` page because no entity with that ID is found or you have been redirected to the correct, canonical slug for this entity. 75 | 76 | ### Complete example 77 | 78 | ```ts 79 | import { db } from '$lib/db.js'; 80 | import { healer } from '$lib/selfheal.js'; 81 | import { error, redirect } from '@sveltejs/kit'; 82 | import type { PageServerLoad } from './$types.js'; 83 | 84 | export const load: PageServerLoad = async ({ params, url }) => { 85 | const identifier = healer.parseId(params.id); 86 | 87 | const article = db.articles.find((article) => String(article.id) === identifier); 88 | if (!article) throw error(404, `Article "${identifier}" not found`); 89 | 90 | const expectedUrl = healer.createUrl(article.id, article.title, url.searchParams); 91 | const valid = healer.validate(expectedUrl, params.id, url.searchParams); 92 | if (!valid) throw redirect(301, expectedUrl); 93 | 94 | return { article, slug: params.id }; 95 | }; 96 | ``` 97 | 98 | Don't worry if your "slug" isn't URL friendly; the package will take care of 99 | formatting it for you whenever you call `createUrl()`. In fact, it doesn't even have to be unique because the 100 | defined unique identifier for your model will also be included at the end. 101 | If some entities have no article, you can just provide an empty string and the IDs will work as if there were no self-healing going on. 102 | 103 | ## Limitations 104 | 105 | By default, the package requires that your unique identifier (such as the `id` or `uuid` column) 106 | not have any `-` characters. However, you can implement your own `IdentifierHandler` as detailed in the next section and override how IDs are joined and separated. 107 | 108 | ## Configuration 109 | 110 | During initialization you can configure the `healer` by passing in functions to handle its operations, or use its sensible defaults. 111 | 112 | By default, the package uses 113 | 114 | | Function | Method | Description | 115 | | ----------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- | 116 | | sanitize() | Kebab | Trims, replaces spaces with hyphens, removes multiple hyphens, removes hyphens at the start and end of the string and converts to lowercase | 117 | | isEqual() | Name | Compares the canonical and current routes by their names using a simple `===` | 118 | | identifier() | Hyphen | Appends the ID to the slug using a hyphen `-` | 119 | 120 | You can however change any of these individually, within the limitations mentioned above. 121 | 122 | ```ts 123 | export const healer = selfheal({ 124 | sanitize: (slug) => { 125 | /* ... */ 126 | }, 127 | isEqual: (expectedValue, actualValue) => { 128 | /* ... */ 129 | }, 130 | identifier: { 131 | join(slug, identifier) { 132 | /* ... */ 133 | }, 134 | separate(slug) { 135 | /* ... */ 136 | } 137 | }, 138 | 139 | }); 140 | ``` 141 | 142 | ### Using a custom `IdentifierHandler` 143 | 144 | If you need to customize how a slug is joined to a model identifier (which by default is just a hyphen), 145 | you can create your own `IdentifierHandler` that returns a `join()` and a `separate()` function and supply itduring the initialization of your `healer`. 146 | 147 | Here is an example using a `_` instead 148 | 149 | ```ts 150 | export const healer = selfheal({ 151 | identifier: { 152 | join(slug, identifier) { 153 | return `${slug}_${identifier}`; 154 | }, 155 | separate(slug) { 156 | const [identifier, ...rest] = slug.split('_').reverse(); 157 | return { 158 | identifier, 159 | slug: rest.reverse().join('_') 160 | }; 161 | } 162 | } 163 | }); 164 | ``` 165 | 166 | This would result in URLs like `/my-fancy-title_123`, depending of course on how your sanitizer works. 167 | 168 | ## License 169 | 170 | Licensed under the [MIT license](https://github.com/dominic-schmid/svelte-selfheal/blob/main/LICENSE.md). 171 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-selfheal", 3 | "version": "0.2.0", 4 | "description": "Generate SEO friendly URLs with IDs and redirect to the canonical URL even if the URL is not correct.", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Dominic Schmid", 8 | "url": "https://dominic-schmid.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/dominic-schmid/svelte-selfheal" 13 | }, 14 | "scripts": { 15 | "dev": "vite dev", 16 | "build": "vite build && npm run package", 17 | "preview": "vite preview", 18 | "package": "svelte-kit sync && svelte-package && publint", 19 | "prepublishOnly": "npm run package", 20 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 21 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 22 | "test": "vitest", 23 | "lint": "prettier --check . && eslint .", 24 | "format": "prettier --write ." 25 | }, 26 | "exports": { 27 | ".": { 28 | "types": "./dist/index.d.ts", 29 | "svelte": "./dist/index.js" 30 | } 31 | }, 32 | "files": [ 33 | "dist", 34 | "!dist/**/*.test.*", 35 | "!dist/**/*.spec.*" 36 | ], 37 | "peerDependencies": { 38 | "svelte": "^4.0.0" 39 | }, 40 | "devDependencies": { 41 | "@sveltejs/adapter-auto": "^2.0.0", 42 | "@sveltejs/kit": "^1.27.4", 43 | "@sveltejs/package": "^2.0.0", 44 | "@typescript-eslint/eslint-plugin": "^6.0.0", 45 | "@typescript-eslint/parser": "^6.0.0", 46 | "eslint": "^8.28.0", 47 | "eslint-config-prettier": "^9.0.0", 48 | "eslint-plugin-svelte": "^2.30.0", 49 | "prettier": "^3.0.0", 50 | "prettier-plugin-svelte": "^3.0.0", 51 | "publint": "^0.1.9", 52 | "svelte": "^4.2.7", 53 | "svelte-check": "^3.6.0", 54 | "tslib": "^2.4.1", 55 | "typescript": "^5.0.0", 56 | "vite": "^4.4.2", 57 | "vitest": "^0.34.0" 58 | }, 59 | "svelte": "./dist/index.js", 60 | "types": "./dist/index.d.ts", 61 | "type": "module" 62 | } 63 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | devDependencies: 8 | '@sveltejs/adapter-auto': 9 | specifier: ^2.0.0 10 | version: 2.1.1(@sveltejs/kit@1.27.6) 11 | '@sveltejs/kit': 12 | specifier: ^1.27.4 13 | version: 1.27.6(svelte@4.2.7)(vite@4.5.0) 14 | '@sveltejs/package': 15 | specifier: ^2.0.0 16 | version: 2.2.3(svelte@4.2.7)(typescript@5.3.2) 17 | '@typescript-eslint/eslint-plugin': 18 | specifier: ^6.0.0 19 | version: 6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.54.0)(typescript@5.3.2) 20 | '@typescript-eslint/parser': 21 | specifier: ^6.0.0 22 | version: 6.13.1(eslint@8.54.0)(typescript@5.3.2) 23 | eslint: 24 | specifier: ^8.28.0 25 | version: 8.54.0 26 | eslint-config-prettier: 27 | specifier: ^9.0.0 28 | version: 9.0.0(eslint@8.54.0) 29 | eslint-plugin-svelte: 30 | specifier: ^2.30.0 31 | version: 2.35.1(eslint@8.54.0)(svelte@4.2.7) 32 | prettier: 33 | specifier: ^3.0.0 34 | version: 3.1.0 35 | prettier-plugin-svelte: 36 | specifier: ^3.0.0 37 | version: 3.1.2(prettier@3.1.0)(svelte@4.2.7) 38 | publint: 39 | specifier: ^0.1.9 40 | version: 0.1.16 41 | svelte: 42 | specifier: ^4.2.7 43 | version: 4.2.7 44 | svelte-check: 45 | specifier: ^3.6.0 46 | version: 3.6.2(postcss@8.4.31)(svelte@4.2.7) 47 | tslib: 48 | specifier: ^2.4.1 49 | version: 2.6.2 50 | typescript: 51 | specifier: ^5.0.0 52 | version: 5.3.2 53 | vite: 54 | specifier: ^4.4.2 55 | version: 4.5.0(@types/node@20.10.0) 56 | vitest: 57 | specifier: ^0.34.0 58 | version: 0.34.6 59 | 60 | packages: 61 | 62 | /@aashutoshrathi/word-wrap@1.2.6: 63 | resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} 64 | engines: {node: '>=0.10.0'} 65 | dev: true 66 | 67 | /@ampproject/remapping@2.2.1: 68 | resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} 69 | engines: {node: '>=6.0.0'} 70 | dependencies: 71 | '@jridgewell/gen-mapping': 0.3.3 72 | '@jridgewell/trace-mapping': 0.3.20 73 | dev: true 74 | 75 | /@esbuild/android-arm64@0.18.20: 76 | resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} 77 | engines: {node: '>=12'} 78 | cpu: [arm64] 79 | os: [android] 80 | requiresBuild: true 81 | dev: true 82 | optional: true 83 | 84 | /@esbuild/android-arm@0.18.20: 85 | resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} 86 | engines: {node: '>=12'} 87 | cpu: [arm] 88 | os: [android] 89 | requiresBuild: true 90 | dev: true 91 | optional: true 92 | 93 | /@esbuild/android-x64@0.18.20: 94 | resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} 95 | engines: {node: '>=12'} 96 | cpu: [x64] 97 | os: [android] 98 | requiresBuild: true 99 | dev: true 100 | optional: true 101 | 102 | /@esbuild/darwin-arm64@0.18.20: 103 | resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} 104 | engines: {node: '>=12'} 105 | cpu: [arm64] 106 | os: [darwin] 107 | requiresBuild: true 108 | dev: true 109 | optional: true 110 | 111 | /@esbuild/darwin-x64@0.18.20: 112 | resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} 113 | engines: {node: '>=12'} 114 | cpu: [x64] 115 | os: [darwin] 116 | requiresBuild: true 117 | dev: true 118 | optional: true 119 | 120 | /@esbuild/freebsd-arm64@0.18.20: 121 | resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} 122 | engines: {node: '>=12'} 123 | cpu: [arm64] 124 | os: [freebsd] 125 | requiresBuild: true 126 | dev: true 127 | optional: true 128 | 129 | /@esbuild/freebsd-x64@0.18.20: 130 | resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} 131 | engines: {node: '>=12'} 132 | cpu: [x64] 133 | os: [freebsd] 134 | requiresBuild: true 135 | dev: true 136 | optional: true 137 | 138 | /@esbuild/linux-arm64@0.18.20: 139 | resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} 140 | engines: {node: '>=12'} 141 | cpu: [arm64] 142 | os: [linux] 143 | requiresBuild: true 144 | dev: true 145 | optional: true 146 | 147 | /@esbuild/linux-arm@0.18.20: 148 | resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} 149 | engines: {node: '>=12'} 150 | cpu: [arm] 151 | os: [linux] 152 | requiresBuild: true 153 | dev: true 154 | optional: true 155 | 156 | /@esbuild/linux-ia32@0.18.20: 157 | resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} 158 | engines: {node: '>=12'} 159 | cpu: [ia32] 160 | os: [linux] 161 | requiresBuild: true 162 | dev: true 163 | optional: true 164 | 165 | /@esbuild/linux-loong64@0.18.20: 166 | resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} 167 | engines: {node: '>=12'} 168 | cpu: [loong64] 169 | os: [linux] 170 | requiresBuild: true 171 | dev: true 172 | optional: true 173 | 174 | /@esbuild/linux-mips64el@0.18.20: 175 | resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} 176 | engines: {node: '>=12'} 177 | cpu: [mips64el] 178 | os: [linux] 179 | requiresBuild: true 180 | dev: true 181 | optional: true 182 | 183 | /@esbuild/linux-ppc64@0.18.20: 184 | resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} 185 | engines: {node: '>=12'} 186 | cpu: [ppc64] 187 | os: [linux] 188 | requiresBuild: true 189 | dev: true 190 | optional: true 191 | 192 | /@esbuild/linux-riscv64@0.18.20: 193 | resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} 194 | engines: {node: '>=12'} 195 | cpu: [riscv64] 196 | os: [linux] 197 | requiresBuild: true 198 | dev: true 199 | optional: true 200 | 201 | /@esbuild/linux-s390x@0.18.20: 202 | resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} 203 | engines: {node: '>=12'} 204 | cpu: [s390x] 205 | os: [linux] 206 | requiresBuild: true 207 | dev: true 208 | optional: true 209 | 210 | /@esbuild/linux-x64@0.18.20: 211 | resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} 212 | engines: {node: '>=12'} 213 | cpu: [x64] 214 | os: [linux] 215 | requiresBuild: true 216 | dev: true 217 | optional: true 218 | 219 | /@esbuild/netbsd-x64@0.18.20: 220 | resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} 221 | engines: {node: '>=12'} 222 | cpu: [x64] 223 | os: [netbsd] 224 | requiresBuild: true 225 | dev: true 226 | optional: true 227 | 228 | /@esbuild/openbsd-x64@0.18.20: 229 | resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} 230 | engines: {node: '>=12'} 231 | cpu: [x64] 232 | os: [openbsd] 233 | requiresBuild: true 234 | dev: true 235 | optional: true 236 | 237 | /@esbuild/sunos-x64@0.18.20: 238 | resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} 239 | engines: {node: '>=12'} 240 | cpu: [x64] 241 | os: [sunos] 242 | requiresBuild: true 243 | dev: true 244 | optional: true 245 | 246 | /@esbuild/win32-arm64@0.18.20: 247 | resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} 248 | engines: {node: '>=12'} 249 | cpu: [arm64] 250 | os: [win32] 251 | requiresBuild: true 252 | dev: true 253 | optional: true 254 | 255 | /@esbuild/win32-ia32@0.18.20: 256 | resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} 257 | engines: {node: '>=12'} 258 | cpu: [ia32] 259 | os: [win32] 260 | requiresBuild: true 261 | dev: true 262 | optional: true 263 | 264 | /@esbuild/win32-x64@0.18.20: 265 | resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} 266 | engines: {node: '>=12'} 267 | cpu: [x64] 268 | os: [win32] 269 | requiresBuild: true 270 | dev: true 271 | optional: true 272 | 273 | /@eslint-community/eslint-utils@4.4.0(eslint@8.54.0): 274 | resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} 275 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 276 | peerDependencies: 277 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 278 | dependencies: 279 | eslint: 8.54.0 280 | eslint-visitor-keys: 3.4.3 281 | dev: true 282 | 283 | /@eslint-community/regexpp@4.10.0: 284 | resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} 285 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 286 | dev: true 287 | 288 | /@eslint/eslintrc@2.1.3: 289 | resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} 290 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 291 | dependencies: 292 | ajv: 6.12.6 293 | debug: 4.3.4 294 | espree: 9.6.1 295 | globals: 13.23.0 296 | ignore: 5.3.0 297 | import-fresh: 3.3.0 298 | js-yaml: 4.1.0 299 | minimatch: 3.1.2 300 | strip-json-comments: 3.1.1 301 | transitivePeerDependencies: 302 | - supports-color 303 | dev: true 304 | 305 | /@eslint/js@8.54.0: 306 | resolution: {integrity: sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==} 307 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 308 | dev: true 309 | 310 | /@fastify/busboy@2.1.0: 311 | resolution: {integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==} 312 | engines: {node: '>=14'} 313 | dev: true 314 | 315 | /@humanwhocodes/config-array@0.11.13: 316 | resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} 317 | engines: {node: '>=10.10.0'} 318 | dependencies: 319 | '@humanwhocodes/object-schema': 2.0.1 320 | debug: 4.3.4 321 | minimatch: 3.1.2 322 | transitivePeerDependencies: 323 | - supports-color 324 | dev: true 325 | 326 | /@humanwhocodes/module-importer@1.0.1: 327 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 328 | engines: {node: '>=12.22'} 329 | dev: true 330 | 331 | /@humanwhocodes/object-schema@2.0.1: 332 | resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} 333 | dev: true 334 | 335 | /@jest/schemas@29.6.3: 336 | resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} 337 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 338 | dependencies: 339 | '@sinclair/typebox': 0.27.8 340 | dev: true 341 | 342 | /@jridgewell/gen-mapping@0.3.3: 343 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} 344 | engines: {node: '>=6.0.0'} 345 | dependencies: 346 | '@jridgewell/set-array': 1.1.2 347 | '@jridgewell/sourcemap-codec': 1.4.15 348 | '@jridgewell/trace-mapping': 0.3.20 349 | dev: true 350 | 351 | /@jridgewell/resolve-uri@3.1.1: 352 | resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} 353 | engines: {node: '>=6.0.0'} 354 | dev: true 355 | 356 | /@jridgewell/set-array@1.1.2: 357 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} 358 | engines: {node: '>=6.0.0'} 359 | dev: true 360 | 361 | /@jridgewell/sourcemap-codec@1.4.15: 362 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 363 | dev: true 364 | 365 | /@jridgewell/trace-mapping@0.3.20: 366 | resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} 367 | dependencies: 368 | '@jridgewell/resolve-uri': 3.1.1 369 | '@jridgewell/sourcemap-codec': 1.4.15 370 | dev: true 371 | 372 | /@nodelib/fs.scandir@2.1.5: 373 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 374 | engines: {node: '>= 8'} 375 | dependencies: 376 | '@nodelib/fs.stat': 2.0.5 377 | run-parallel: 1.2.0 378 | dev: true 379 | 380 | /@nodelib/fs.stat@2.0.5: 381 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 382 | engines: {node: '>= 8'} 383 | dev: true 384 | 385 | /@nodelib/fs.walk@1.2.8: 386 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 387 | engines: {node: '>= 8'} 388 | dependencies: 389 | '@nodelib/fs.scandir': 2.1.5 390 | fastq: 1.15.0 391 | dev: true 392 | 393 | /@polka/url@1.0.0-next.23: 394 | resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==} 395 | dev: true 396 | 397 | /@sinclair/typebox@0.27.8: 398 | resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} 399 | dev: true 400 | 401 | /@sveltejs/adapter-auto@2.1.1(@sveltejs/kit@1.27.6): 402 | resolution: {integrity: sha512-nzi6x/7/3Axh5VKQ8Eed3pYxastxoa06Y/bFhWb7h3Nu+nGRVxKAy3+hBJgmPCwWScy8n0TsstZjSVKfyrIHkg==} 403 | peerDependencies: 404 | '@sveltejs/kit': ^1.0.0 405 | dependencies: 406 | '@sveltejs/kit': 1.27.6(svelte@4.2.7)(vite@4.5.0) 407 | import-meta-resolve: 4.0.0 408 | dev: true 409 | 410 | /@sveltejs/kit@1.27.6(svelte@4.2.7)(vite@4.5.0): 411 | resolution: {integrity: sha512-GsjTkMbKzXdbeRg0tk8S7HNShQ4879ftRr0ZHaZfjbig1xQwG57Bvcm9U9/mpLJtCapLbLWUnygKrgcLISLC8A==} 412 | engines: {node: ^16.14 || >=18} 413 | hasBin: true 414 | requiresBuild: true 415 | peerDependencies: 416 | svelte: ^3.54.0 || ^4.0.0-next.0 || ^5.0.0-next.0 417 | vite: ^4.0.0 418 | dependencies: 419 | '@sveltejs/vite-plugin-svelte': 2.5.3(svelte@4.2.7)(vite@4.5.0) 420 | '@types/cookie': 0.5.4 421 | cookie: 0.5.0 422 | devalue: 4.3.2 423 | esm-env: 1.0.0 424 | kleur: 4.1.5 425 | magic-string: 0.30.5 426 | mrmime: 1.0.1 427 | sade: 1.8.1 428 | set-cookie-parser: 2.6.0 429 | sirv: 2.0.3 430 | svelte: 4.2.7 431 | tiny-glob: 0.2.9 432 | undici: 5.26.5 433 | vite: 4.5.0(@types/node@20.10.0) 434 | transitivePeerDependencies: 435 | - supports-color 436 | dev: true 437 | 438 | /@sveltejs/package@2.2.3(svelte@4.2.7)(typescript@5.3.2): 439 | resolution: {integrity: sha512-iZEC5qw+2RIjfIAHR3O+IeokJIjVM/ieoxPxj6YmZCwu5JKFADtC4jzjSUJ7GkCMUQ4HqE7u4/3cCxXBocxi8A==} 440 | engines: {node: ^16.14 || >=18} 441 | hasBin: true 442 | peerDependencies: 443 | svelte: ^3.44.0 || ^4.0.0 444 | dependencies: 445 | chokidar: 3.5.3 446 | kleur: 4.1.5 447 | sade: 1.8.1 448 | semver: 7.5.4 449 | svelte: 4.2.7 450 | svelte2tsx: 0.6.27(svelte@4.2.7)(typescript@5.3.2) 451 | transitivePeerDependencies: 452 | - typescript 453 | dev: true 454 | 455 | /@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.5.3)(svelte@4.2.7)(vite@4.5.0): 456 | resolution: {integrity: sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==} 457 | engines: {node: ^14.18.0 || >= 16} 458 | peerDependencies: 459 | '@sveltejs/vite-plugin-svelte': ^2.2.0 460 | svelte: ^3.54.0 || ^4.0.0 461 | vite: ^4.0.0 462 | dependencies: 463 | '@sveltejs/vite-plugin-svelte': 2.5.3(svelte@4.2.7)(vite@4.5.0) 464 | debug: 4.3.4 465 | svelte: 4.2.7 466 | vite: 4.5.0(@types/node@20.10.0) 467 | transitivePeerDependencies: 468 | - supports-color 469 | dev: true 470 | 471 | /@sveltejs/vite-plugin-svelte@2.5.3(svelte@4.2.7)(vite@4.5.0): 472 | resolution: {integrity: sha512-erhNtXxE5/6xGZz/M9eXsmI7Pxa6MS7jyTy06zN3Ck++ldrppOnOlJwHHTsMC7DHDQdgUp4NAc4cDNQ9eGdB/w==} 473 | engines: {node: ^14.18.0 || >= 16} 474 | peerDependencies: 475 | svelte: ^3.54.0 || ^4.0.0 || ^5.0.0-next.0 476 | vite: ^4.0.0 477 | dependencies: 478 | '@sveltejs/vite-plugin-svelte-inspector': 1.0.4(@sveltejs/vite-plugin-svelte@2.5.3)(svelte@4.2.7)(vite@4.5.0) 479 | debug: 4.3.4 480 | deepmerge: 4.3.1 481 | kleur: 4.1.5 482 | magic-string: 0.30.5 483 | svelte: 4.2.7 484 | svelte-hmr: 0.15.3(svelte@4.2.7) 485 | vite: 4.5.0(@types/node@20.10.0) 486 | vitefu: 0.2.5(vite@4.5.0) 487 | transitivePeerDependencies: 488 | - supports-color 489 | dev: true 490 | 491 | /@types/chai-subset@1.3.5: 492 | resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==} 493 | dependencies: 494 | '@types/chai': 4.3.11 495 | dev: true 496 | 497 | /@types/chai@4.3.11: 498 | resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==} 499 | dev: true 500 | 501 | /@types/cookie@0.5.4: 502 | resolution: {integrity: sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==} 503 | dev: true 504 | 505 | /@types/estree@1.0.5: 506 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 507 | dev: true 508 | 509 | /@types/json-schema@7.0.15: 510 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 511 | dev: true 512 | 513 | /@types/node@20.10.0: 514 | resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==} 515 | dependencies: 516 | undici-types: 5.26.5 517 | dev: true 518 | 519 | /@types/pug@2.0.10: 520 | resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} 521 | dev: true 522 | 523 | /@types/semver@7.5.6: 524 | resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} 525 | dev: true 526 | 527 | /@typescript-eslint/eslint-plugin@6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.54.0)(typescript@5.3.2): 528 | resolution: {integrity: sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==} 529 | engines: {node: ^16.0.0 || >=18.0.0} 530 | peerDependencies: 531 | '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha 532 | eslint: ^7.0.0 || ^8.0.0 533 | typescript: '*' 534 | peerDependenciesMeta: 535 | typescript: 536 | optional: true 537 | dependencies: 538 | '@eslint-community/regexpp': 4.10.0 539 | '@typescript-eslint/parser': 6.13.1(eslint@8.54.0)(typescript@5.3.2) 540 | '@typescript-eslint/scope-manager': 6.13.1 541 | '@typescript-eslint/type-utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) 542 | '@typescript-eslint/utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) 543 | '@typescript-eslint/visitor-keys': 6.13.1 544 | debug: 4.3.4 545 | eslint: 8.54.0 546 | graphemer: 1.4.0 547 | ignore: 5.3.0 548 | natural-compare: 1.4.0 549 | semver: 7.5.4 550 | ts-api-utils: 1.0.3(typescript@5.3.2) 551 | typescript: 5.3.2 552 | transitivePeerDependencies: 553 | - supports-color 554 | dev: true 555 | 556 | /@typescript-eslint/parser@6.13.1(eslint@8.54.0)(typescript@5.3.2): 557 | resolution: {integrity: sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==} 558 | engines: {node: ^16.0.0 || >=18.0.0} 559 | peerDependencies: 560 | eslint: ^7.0.0 || ^8.0.0 561 | typescript: '*' 562 | peerDependenciesMeta: 563 | typescript: 564 | optional: true 565 | dependencies: 566 | '@typescript-eslint/scope-manager': 6.13.1 567 | '@typescript-eslint/types': 6.13.1 568 | '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) 569 | '@typescript-eslint/visitor-keys': 6.13.1 570 | debug: 4.3.4 571 | eslint: 8.54.0 572 | typescript: 5.3.2 573 | transitivePeerDependencies: 574 | - supports-color 575 | dev: true 576 | 577 | /@typescript-eslint/scope-manager@6.13.1: 578 | resolution: {integrity: sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==} 579 | engines: {node: ^16.0.0 || >=18.0.0} 580 | dependencies: 581 | '@typescript-eslint/types': 6.13.1 582 | '@typescript-eslint/visitor-keys': 6.13.1 583 | dev: true 584 | 585 | /@typescript-eslint/type-utils@6.13.1(eslint@8.54.0)(typescript@5.3.2): 586 | resolution: {integrity: sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==} 587 | engines: {node: ^16.0.0 || >=18.0.0} 588 | peerDependencies: 589 | eslint: ^7.0.0 || ^8.0.0 590 | typescript: '*' 591 | peerDependenciesMeta: 592 | typescript: 593 | optional: true 594 | dependencies: 595 | '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) 596 | '@typescript-eslint/utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) 597 | debug: 4.3.4 598 | eslint: 8.54.0 599 | ts-api-utils: 1.0.3(typescript@5.3.2) 600 | typescript: 5.3.2 601 | transitivePeerDependencies: 602 | - supports-color 603 | dev: true 604 | 605 | /@typescript-eslint/types@6.13.1: 606 | resolution: {integrity: sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==} 607 | engines: {node: ^16.0.0 || >=18.0.0} 608 | dev: true 609 | 610 | /@typescript-eslint/typescript-estree@6.13.1(typescript@5.3.2): 611 | resolution: {integrity: sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==} 612 | engines: {node: ^16.0.0 || >=18.0.0} 613 | peerDependencies: 614 | typescript: '*' 615 | peerDependenciesMeta: 616 | typescript: 617 | optional: true 618 | dependencies: 619 | '@typescript-eslint/types': 6.13.1 620 | '@typescript-eslint/visitor-keys': 6.13.1 621 | debug: 4.3.4 622 | globby: 11.1.0 623 | is-glob: 4.0.3 624 | semver: 7.5.4 625 | ts-api-utils: 1.0.3(typescript@5.3.2) 626 | typescript: 5.3.2 627 | transitivePeerDependencies: 628 | - supports-color 629 | dev: true 630 | 631 | /@typescript-eslint/utils@6.13.1(eslint@8.54.0)(typescript@5.3.2): 632 | resolution: {integrity: sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==} 633 | engines: {node: ^16.0.0 || >=18.0.0} 634 | peerDependencies: 635 | eslint: ^7.0.0 || ^8.0.0 636 | dependencies: 637 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) 638 | '@types/json-schema': 7.0.15 639 | '@types/semver': 7.5.6 640 | '@typescript-eslint/scope-manager': 6.13.1 641 | '@typescript-eslint/types': 6.13.1 642 | '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) 643 | eslint: 8.54.0 644 | semver: 7.5.4 645 | transitivePeerDependencies: 646 | - supports-color 647 | - typescript 648 | dev: true 649 | 650 | /@typescript-eslint/visitor-keys@6.13.1: 651 | resolution: {integrity: sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==} 652 | engines: {node: ^16.0.0 || >=18.0.0} 653 | dependencies: 654 | '@typescript-eslint/types': 6.13.1 655 | eslint-visitor-keys: 3.4.3 656 | dev: true 657 | 658 | /@ungap/structured-clone@1.2.0: 659 | resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} 660 | dev: true 661 | 662 | /@vitest/expect@0.34.6: 663 | resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==} 664 | dependencies: 665 | '@vitest/spy': 0.34.6 666 | '@vitest/utils': 0.34.6 667 | chai: 4.3.10 668 | dev: true 669 | 670 | /@vitest/runner@0.34.6: 671 | resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==} 672 | dependencies: 673 | '@vitest/utils': 0.34.6 674 | p-limit: 4.0.0 675 | pathe: 1.1.1 676 | dev: true 677 | 678 | /@vitest/snapshot@0.34.6: 679 | resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==} 680 | dependencies: 681 | magic-string: 0.30.5 682 | pathe: 1.1.1 683 | pretty-format: 29.7.0 684 | dev: true 685 | 686 | /@vitest/spy@0.34.6: 687 | resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==} 688 | dependencies: 689 | tinyspy: 2.2.0 690 | dev: true 691 | 692 | /@vitest/utils@0.34.6: 693 | resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==} 694 | dependencies: 695 | diff-sequences: 29.6.3 696 | loupe: 2.3.7 697 | pretty-format: 29.7.0 698 | dev: true 699 | 700 | /acorn-jsx@5.3.2(acorn@8.11.2): 701 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 702 | peerDependencies: 703 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 704 | dependencies: 705 | acorn: 8.11.2 706 | dev: true 707 | 708 | /acorn-walk@8.3.0: 709 | resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} 710 | engines: {node: '>=0.4.0'} 711 | dev: true 712 | 713 | /acorn@8.11.2: 714 | resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} 715 | engines: {node: '>=0.4.0'} 716 | hasBin: true 717 | dev: true 718 | 719 | /ajv@6.12.6: 720 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 721 | dependencies: 722 | fast-deep-equal: 3.1.3 723 | fast-json-stable-stringify: 2.1.0 724 | json-schema-traverse: 0.4.1 725 | uri-js: 4.4.1 726 | dev: true 727 | 728 | /ansi-regex@5.0.1: 729 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 730 | engines: {node: '>=8'} 731 | dev: true 732 | 733 | /ansi-styles@4.3.0: 734 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 735 | engines: {node: '>=8'} 736 | dependencies: 737 | color-convert: 2.0.1 738 | dev: true 739 | 740 | /ansi-styles@5.2.0: 741 | resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} 742 | engines: {node: '>=10'} 743 | dev: true 744 | 745 | /anymatch@3.1.3: 746 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 747 | engines: {node: '>= 8'} 748 | dependencies: 749 | normalize-path: 3.0.0 750 | picomatch: 2.3.1 751 | dev: true 752 | 753 | /argparse@2.0.1: 754 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 755 | dev: true 756 | 757 | /aria-query@5.3.0: 758 | resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} 759 | dependencies: 760 | dequal: 2.0.3 761 | dev: true 762 | 763 | /array-union@2.1.0: 764 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 765 | engines: {node: '>=8'} 766 | dev: true 767 | 768 | /assertion-error@1.1.0: 769 | resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} 770 | dev: true 771 | 772 | /axobject-query@3.2.1: 773 | resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} 774 | dependencies: 775 | dequal: 2.0.3 776 | dev: true 777 | 778 | /balanced-match@1.0.2: 779 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 780 | dev: true 781 | 782 | /binary-extensions@2.2.0: 783 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 784 | engines: {node: '>=8'} 785 | dev: true 786 | 787 | /brace-expansion@1.1.11: 788 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 789 | dependencies: 790 | balanced-match: 1.0.2 791 | concat-map: 0.0.1 792 | dev: true 793 | 794 | /brace-expansion@2.0.1: 795 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 796 | dependencies: 797 | balanced-match: 1.0.2 798 | dev: true 799 | 800 | /braces@3.0.2: 801 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 802 | engines: {node: '>=8'} 803 | dependencies: 804 | fill-range: 7.0.1 805 | dev: true 806 | 807 | /buffer-crc32@0.2.13: 808 | resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} 809 | dev: true 810 | 811 | /cac@6.7.14: 812 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 813 | engines: {node: '>=8'} 814 | dev: true 815 | 816 | /callsites@3.1.0: 817 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 818 | engines: {node: '>=6'} 819 | dev: true 820 | 821 | /chai@4.3.10: 822 | resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} 823 | engines: {node: '>=4'} 824 | dependencies: 825 | assertion-error: 1.1.0 826 | check-error: 1.0.3 827 | deep-eql: 4.1.3 828 | get-func-name: 2.0.2 829 | loupe: 2.3.7 830 | pathval: 1.1.1 831 | type-detect: 4.0.8 832 | dev: true 833 | 834 | /chalk@4.1.2: 835 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 836 | engines: {node: '>=10'} 837 | dependencies: 838 | ansi-styles: 4.3.0 839 | supports-color: 7.2.0 840 | dev: true 841 | 842 | /check-error@1.0.3: 843 | resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} 844 | dependencies: 845 | get-func-name: 2.0.2 846 | dev: true 847 | 848 | /chokidar@3.5.3: 849 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 850 | engines: {node: '>= 8.10.0'} 851 | dependencies: 852 | anymatch: 3.1.3 853 | braces: 3.0.2 854 | glob-parent: 5.1.2 855 | is-binary-path: 2.1.0 856 | is-glob: 4.0.3 857 | normalize-path: 3.0.0 858 | readdirp: 3.6.0 859 | optionalDependencies: 860 | fsevents: 2.3.3 861 | dev: true 862 | 863 | /code-red@1.0.4: 864 | resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} 865 | dependencies: 866 | '@jridgewell/sourcemap-codec': 1.4.15 867 | '@types/estree': 1.0.5 868 | acorn: 8.11.2 869 | estree-walker: 3.0.3 870 | periscopic: 3.1.0 871 | dev: true 872 | 873 | /color-convert@2.0.1: 874 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 875 | engines: {node: '>=7.0.0'} 876 | dependencies: 877 | color-name: 1.1.4 878 | dev: true 879 | 880 | /color-name@1.1.4: 881 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 882 | dev: true 883 | 884 | /concat-map@0.0.1: 885 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 886 | dev: true 887 | 888 | /cookie@0.5.0: 889 | resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} 890 | engines: {node: '>= 0.6'} 891 | dev: true 892 | 893 | /cross-spawn@7.0.3: 894 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 895 | engines: {node: '>= 8'} 896 | dependencies: 897 | path-key: 3.1.1 898 | shebang-command: 2.0.0 899 | which: 2.0.2 900 | dev: true 901 | 902 | /css-tree@2.3.1: 903 | resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} 904 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} 905 | dependencies: 906 | mdn-data: 2.0.30 907 | source-map-js: 1.0.2 908 | dev: true 909 | 910 | /cssesc@3.0.0: 911 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 912 | engines: {node: '>=4'} 913 | hasBin: true 914 | dev: true 915 | 916 | /debug@4.3.4: 917 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 918 | engines: {node: '>=6.0'} 919 | peerDependencies: 920 | supports-color: '*' 921 | peerDependenciesMeta: 922 | supports-color: 923 | optional: true 924 | dependencies: 925 | ms: 2.1.2 926 | dev: true 927 | 928 | /dedent-js@1.0.1: 929 | resolution: {integrity: sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==} 930 | dev: true 931 | 932 | /deep-eql@4.1.3: 933 | resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} 934 | engines: {node: '>=6'} 935 | dependencies: 936 | type-detect: 4.0.8 937 | dev: true 938 | 939 | /deep-is@0.1.4: 940 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 941 | dev: true 942 | 943 | /deepmerge@4.3.1: 944 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 945 | engines: {node: '>=0.10.0'} 946 | dev: true 947 | 948 | /dequal@2.0.3: 949 | resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 950 | engines: {node: '>=6'} 951 | dev: true 952 | 953 | /detect-indent@6.1.0: 954 | resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} 955 | engines: {node: '>=8'} 956 | dev: true 957 | 958 | /devalue@4.3.2: 959 | resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==} 960 | dev: true 961 | 962 | /diff-sequences@29.6.3: 963 | resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} 964 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 965 | dev: true 966 | 967 | /dir-glob@3.0.1: 968 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 969 | engines: {node: '>=8'} 970 | dependencies: 971 | path-type: 4.0.0 972 | dev: true 973 | 974 | /doctrine@3.0.0: 975 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} 976 | engines: {node: '>=6.0.0'} 977 | dependencies: 978 | esutils: 2.0.3 979 | dev: true 980 | 981 | /es6-promise@3.3.1: 982 | resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} 983 | dev: true 984 | 985 | /esbuild@0.18.20: 986 | resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} 987 | engines: {node: '>=12'} 988 | hasBin: true 989 | requiresBuild: true 990 | optionalDependencies: 991 | '@esbuild/android-arm': 0.18.20 992 | '@esbuild/android-arm64': 0.18.20 993 | '@esbuild/android-x64': 0.18.20 994 | '@esbuild/darwin-arm64': 0.18.20 995 | '@esbuild/darwin-x64': 0.18.20 996 | '@esbuild/freebsd-arm64': 0.18.20 997 | '@esbuild/freebsd-x64': 0.18.20 998 | '@esbuild/linux-arm': 0.18.20 999 | '@esbuild/linux-arm64': 0.18.20 1000 | '@esbuild/linux-ia32': 0.18.20 1001 | '@esbuild/linux-loong64': 0.18.20 1002 | '@esbuild/linux-mips64el': 0.18.20 1003 | '@esbuild/linux-ppc64': 0.18.20 1004 | '@esbuild/linux-riscv64': 0.18.20 1005 | '@esbuild/linux-s390x': 0.18.20 1006 | '@esbuild/linux-x64': 0.18.20 1007 | '@esbuild/netbsd-x64': 0.18.20 1008 | '@esbuild/openbsd-x64': 0.18.20 1009 | '@esbuild/sunos-x64': 0.18.20 1010 | '@esbuild/win32-arm64': 0.18.20 1011 | '@esbuild/win32-ia32': 0.18.20 1012 | '@esbuild/win32-x64': 0.18.20 1013 | dev: true 1014 | 1015 | /escape-string-regexp@4.0.0: 1016 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 1017 | engines: {node: '>=10'} 1018 | dev: true 1019 | 1020 | /eslint-compat-utils@0.1.2(eslint@8.54.0): 1021 | resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==} 1022 | engines: {node: '>=12'} 1023 | peerDependencies: 1024 | eslint: '>=6.0.0' 1025 | dependencies: 1026 | eslint: 8.54.0 1027 | dev: true 1028 | 1029 | /eslint-config-prettier@9.0.0(eslint@8.54.0): 1030 | resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} 1031 | hasBin: true 1032 | peerDependencies: 1033 | eslint: '>=7.0.0' 1034 | dependencies: 1035 | eslint: 8.54.0 1036 | dev: true 1037 | 1038 | /eslint-plugin-svelte@2.35.1(eslint@8.54.0)(svelte@4.2.7): 1039 | resolution: {integrity: sha512-IF8TpLnROSGy98Z3NrsKXWDSCbNY2ReHDcrYTuXZMbfX7VmESISR78TWgO9zdg4Dht1X8coub5jKwHzP0ExRug==} 1040 | engines: {node: ^14.17.0 || >=16.0.0} 1041 | peerDependencies: 1042 | eslint: ^7.0.0 || ^8.0.0-0 1043 | svelte: ^3.37.0 || ^4.0.0 1044 | peerDependenciesMeta: 1045 | svelte: 1046 | optional: true 1047 | dependencies: 1048 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) 1049 | '@jridgewell/sourcemap-codec': 1.4.15 1050 | debug: 4.3.4 1051 | eslint: 8.54.0 1052 | eslint-compat-utils: 0.1.2(eslint@8.54.0) 1053 | esutils: 2.0.3 1054 | known-css-properties: 0.29.0 1055 | postcss: 8.4.31 1056 | postcss-load-config: 3.1.4(postcss@8.4.31) 1057 | postcss-safe-parser: 6.0.0(postcss@8.4.31) 1058 | postcss-selector-parser: 6.0.13 1059 | semver: 7.5.4 1060 | svelte: 4.2.7 1061 | svelte-eslint-parser: 0.33.1(svelte@4.2.7) 1062 | transitivePeerDependencies: 1063 | - supports-color 1064 | - ts-node 1065 | dev: true 1066 | 1067 | /eslint-scope@7.2.2: 1068 | resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} 1069 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1070 | dependencies: 1071 | esrecurse: 4.3.0 1072 | estraverse: 5.3.0 1073 | dev: true 1074 | 1075 | /eslint-visitor-keys@3.4.3: 1076 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 1077 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1078 | dev: true 1079 | 1080 | /eslint@8.54.0: 1081 | resolution: {integrity: sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==} 1082 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1083 | hasBin: true 1084 | dependencies: 1085 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) 1086 | '@eslint-community/regexpp': 4.10.0 1087 | '@eslint/eslintrc': 2.1.3 1088 | '@eslint/js': 8.54.0 1089 | '@humanwhocodes/config-array': 0.11.13 1090 | '@humanwhocodes/module-importer': 1.0.1 1091 | '@nodelib/fs.walk': 1.2.8 1092 | '@ungap/structured-clone': 1.2.0 1093 | ajv: 6.12.6 1094 | chalk: 4.1.2 1095 | cross-spawn: 7.0.3 1096 | debug: 4.3.4 1097 | doctrine: 3.0.0 1098 | escape-string-regexp: 4.0.0 1099 | eslint-scope: 7.2.2 1100 | eslint-visitor-keys: 3.4.3 1101 | espree: 9.6.1 1102 | esquery: 1.5.0 1103 | esutils: 2.0.3 1104 | fast-deep-equal: 3.1.3 1105 | file-entry-cache: 6.0.1 1106 | find-up: 5.0.0 1107 | glob-parent: 6.0.2 1108 | globals: 13.23.0 1109 | graphemer: 1.4.0 1110 | ignore: 5.3.0 1111 | imurmurhash: 0.1.4 1112 | is-glob: 4.0.3 1113 | is-path-inside: 3.0.3 1114 | js-yaml: 4.1.0 1115 | json-stable-stringify-without-jsonify: 1.0.1 1116 | levn: 0.4.1 1117 | lodash.merge: 4.6.2 1118 | minimatch: 3.1.2 1119 | natural-compare: 1.4.0 1120 | optionator: 0.9.3 1121 | strip-ansi: 6.0.1 1122 | text-table: 0.2.0 1123 | transitivePeerDependencies: 1124 | - supports-color 1125 | dev: true 1126 | 1127 | /esm-env@1.0.0: 1128 | resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} 1129 | dev: true 1130 | 1131 | /espree@9.6.1: 1132 | resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} 1133 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1134 | dependencies: 1135 | acorn: 8.11.2 1136 | acorn-jsx: 5.3.2(acorn@8.11.2) 1137 | eslint-visitor-keys: 3.4.3 1138 | dev: true 1139 | 1140 | /esquery@1.5.0: 1141 | resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} 1142 | engines: {node: '>=0.10'} 1143 | dependencies: 1144 | estraverse: 5.3.0 1145 | dev: true 1146 | 1147 | /esrecurse@4.3.0: 1148 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 1149 | engines: {node: '>=4.0'} 1150 | dependencies: 1151 | estraverse: 5.3.0 1152 | dev: true 1153 | 1154 | /estraverse@5.3.0: 1155 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 1156 | engines: {node: '>=4.0'} 1157 | dev: true 1158 | 1159 | /estree-walker@3.0.3: 1160 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 1161 | dependencies: 1162 | '@types/estree': 1.0.5 1163 | dev: true 1164 | 1165 | /esutils@2.0.3: 1166 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 1167 | engines: {node: '>=0.10.0'} 1168 | dev: true 1169 | 1170 | /fast-deep-equal@3.1.3: 1171 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1172 | dev: true 1173 | 1174 | /fast-glob@3.3.2: 1175 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} 1176 | engines: {node: '>=8.6.0'} 1177 | dependencies: 1178 | '@nodelib/fs.stat': 2.0.5 1179 | '@nodelib/fs.walk': 1.2.8 1180 | glob-parent: 5.1.2 1181 | merge2: 1.4.1 1182 | micromatch: 4.0.5 1183 | dev: true 1184 | 1185 | /fast-json-stable-stringify@2.1.0: 1186 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 1187 | dev: true 1188 | 1189 | /fast-levenshtein@2.0.6: 1190 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 1191 | dev: true 1192 | 1193 | /fastq@1.15.0: 1194 | resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} 1195 | dependencies: 1196 | reusify: 1.0.4 1197 | dev: true 1198 | 1199 | /file-entry-cache@6.0.1: 1200 | resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} 1201 | engines: {node: ^10.12.0 || >=12.0.0} 1202 | dependencies: 1203 | flat-cache: 3.2.0 1204 | dev: true 1205 | 1206 | /fill-range@7.0.1: 1207 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 1208 | engines: {node: '>=8'} 1209 | dependencies: 1210 | to-regex-range: 5.0.1 1211 | dev: true 1212 | 1213 | /find-up@5.0.0: 1214 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 1215 | engines: {node: '>=10'} 1216 | dependencies: 1217 | locate-path: 6.0.0 1218 | path-exists: 4.0.0 1219 | dev: true 1220 | 1221 | /flat-cache@3.2.0: 1222 | resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} 1223 | engines: {node: ^10.12.0 || >=12.0.0} 1224 | dependencies: 1225 | flatted: 3.2.9 1226 | keyv: 4.5.4 1227 | rimraf: 3.0.2 1228 | dev: true 1229 | 1230 | /flatted@3.2.9: 1231 | resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} 1232 | dev: true 1233 | 1234 | /fs.realpath@1.0.0: 1235 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1236 | dev: true 1237 | 1238 | /fsevents@2.3.3: 1239 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1240 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1241 | os: [darwin] 1242 | requiresBuild: true 1243 | dev: true 1244 | optional: true 1245 | 1246 | /get-func-name@2.0.2: 1247 | resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} 1248 | dev: true 1249 | 1250 | /glob-parent@5.1.2: 1251 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1252 | engines: {node: '>= 6'} 1253 | dependencies: 1254 | is-glob: 4.0.3 1255 | dev: true 1256 | 1257 | /glob-parent@6.0.2: 1258 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 1259 | engines: {node: '>=10.13.0'} 1260 | dependencies: 1261 | is-glob: 4.0.3 1262 | dev: true 1263 | 1264 | /glob@7.2.3: 1265 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1266 | dependencies: 1267 | fs.realpath: 1.0.0 1268 | inflight: 1.0.6 1269 | inherits: 2.0.4 1270 | minimatch: 3.1.2 1271 | once: 1.4.0 1272 | path-is-absolute: 1.0.1 1273 | dev: true 1274 | 1275 | /glob@8.1.0: 1276 | resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} 1277 | engines: {node: '>=12'} 1278 | dependencies: 1279 | fs.realpath: 1.0.0 1280 | inflight: 1.0.6 1281 | inherits: 2.0.4 1282 | minimatch: 5.1.6 1283 | once: 1.4.0 1284 | dev: true 1285 | 1286 | /globals@13.23.0: 1287 | resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} 1288 | engines: {node: '>=8'} 1289 | dependencies: 1290 | type-fest: 0.20.2 1291 | dev: true 1292 | 1293 | /globalyzer@0.1.0: 1294 | resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} 1295 | dev: true 1296 | 1297 | /globby@11.1.0: 1298 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 1299 | engines: {node: '>=10'} 1300 | dependencies: 1301 | array-union: 2.1.0 1302 | dir-glob: 3.0.1 1303 | fast-glob: 3.3.2 1304 | ignore: 5.3.0 1305 | merge2: 1.4.1 1306 | slash: 3.0.0 1307 | dev: true 1308 | 1309 | /globrex@0.1.2: 1310 | resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} 1311 | dev: true 1312 | 1313 | /graceful-fs@4.2.11: 1314 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1315 | dev: true 1316 | 1317 | /graphemer@1.4.0: 1318 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 1319 | dev: true 1320 | 1321 | /has-flag@4.0.0: 1322 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1323 | engines: {node: '>=8'} 1324 | dev: true 1325 | 1326 | /ignore-walk@5.0.1: 1327 | resolution: {integrity: sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==} 1328 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 1329 | dependencies: 1330 | minimatch: 5.1.6 1331 | dev: true 1332 | 1333 | /ignore@5.3.0: 1334 | resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} 1335 | engines: {node: '>= 4'} 1336 | dev: true 1337 | 1338 | /import-fresh@3.3.0: 1339 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 1340 | engines: {node: '>=6'} 1341 | dependencies: 1342 | parent-module: 1.0.1 1343 | resolve-from: 4.0.0 1344 | dev: true 1345 | 1346 | /import-meta-resolve@4.0.0: 1347 | resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==} 1348 | dev: true 1349 | 1350 | /imurmurhash@0.1.4: 1351 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1352 | engines: {node: '>=0.8.19'} 1353 | dev: true 1354 | 1355 | /inflight@1.0.6: 1356 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1357 | dependencies: 1358 | once: 1.4.0 1359 | wrappy: 1.0.2 1360 | dev: true 1361 | 1362 | /inherits@2.0.4: 1363 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1364 | dev: true 1365 | 1366 | /is-binary-path@2.1.0: 1367 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 1368 | engines: {node: '>=8'} 1369 | dependencies: 1370 | binary-extensions: 2.2.0 1371 | dev: true 1372 | 1373 | /is-extglob@2.1.1: 1374 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1375 | engines: {node: '>=0.10.0'} 1376 | dev: true 1377 | 1378 | /is-glob@4.0.3: 1379 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1380 | engines: {node: '>=0.10.0'} 1381 | dependencies: 1382 | is-extglob: 2.1.1 1383 | dev: true 1384 | 1385 | /is-number@7.0.0: 1386 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1387 | engines: {node: '>=0.12.0'} 1388 | dev: true 1389 | 1390 | /is-path-inside@3.0.3: 1391 | resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} 1392 | engines: {node: '>=8'} 1393 | dev: true 1394 | 1395 | /is-reference@3.0.2: 1396 | resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} 1397 | dependencies: 1398 | '@types/estree': 1.0.5 1399 | dev: true 1400 | 1401 | /isexe@2.0.0: 1402 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1403 | dev: true 1404 | 1405 | /js-yaml@4.1.0: 1406 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 1407 | hasBin: true 1408 | dependencies: 1409 | argparse: 2.0.1 1410 | dev: true 1411 | 1412 | /json-buffer@3.0.1: 1413 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 1414 | dev: true 1415 | 1416 | /json-schema-traverse@0.4.1: 1417 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1418 | dev: true 1419 | 1420 | /json-stable-stringify-without-jsonify@1.0.1: 1421 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1422 | dev: true 1423 | 1424 | /jsonc-parser@3.2.0: 1425 | resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} 1426 | dev: true 1427 | 1428 | /keyv@4.5.4: 1429 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 1430 | dependencies: 1431 | json-buffer: 3.0.1 1432 | dev: true 1433 | 1434 | /kleur@4.1.5: 1435 | resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 1436 | engines: {node: '>=6'} 1437 | dev: true 1438 | 1439 | /known-css-properties@0.29.0: 1440 | resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==} 1441 | dev: true 1442 | 1443 | /levn@0.4.1: 1444 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1445 | engines: {node: '>= 0.8.0'} 1446 | dependencies: 1447 | prelude-ls: 1.2.1 1448 | type-check: 0.4.0 1449 | dev: true 1450 | 1451 | /lilconfig@2.1.0: 1452 | resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} 1453 | engines: {node: '>=10'} 1454 | dev: true 1455 | 1456 | /local-pkg@0.4.3: 1457 | resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} 1458 | engines: {node: '>=14'} 1459 | dev: true 1460 | 1461 | /locate-character@3.0.0: 1462 | resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} 1463 | dev: true 1464 | 1465 | /locate-path@6.0.0: 1466 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 1467 | engines: {node: '>=10'} 1468 | dependencies: 1469 | p-locate: 5.0.0 1470 | dev: true 1471 | 1472 | /lodash.merge@4.6.2: 1473 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 1474 | dev: true 1475 | 1476 | /loupe@2.3.7: 1477 | resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} 1478 | dependencies: 1479 | get-func-name: 2.0.2 1480 | dev: true 1481 | 1482 | /lower-case@2.0.2: 1483 | resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} 1484 | dependencies: 1485 | tslib: 2.6.2 1486 | dev: true 1487 | 1488 | /lru-cache@6.0.0: 1489 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1490 | engines: {node: '>=10'} 1491 | dependencies: 1492 | yallist: 4.0.0 1493 | dev: true 1494 | 1495 | /magic-string@0.27.0: 1496 | resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} 1497 | engines: {node: '>=12'} 1498 | dependencies: 1499 | '@jridgewell/sourcemap-codec': 1.4.15 1500 | dev: true 1501 | 1502 | /magic-string@0.30.5: 1503 | resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} 1504 | engines: {node: '>=12'} 1505 | dependencies: 1506 | '@jridgewell/sourcemap-codec': 1.4.15 1507 | dev: true 1508 | 1509 | /mdn-data@2.0.30: 1510 | resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} 1511 | dev: true 1512 | 1513 | /merge2@1.4.1: 1514 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1515 | engines: {node: '>= 8'} 1516 | dev: true 1517 | 1518 | /micromatch@4.0.5: 1519 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 1520 | engines: {node: '>=8.6'} 1521 | dependencies: 1522 | braces: 3.0.2 1523 | picomatch: 2.3.1 1524 | dev: true 1525 | 1526 | /min-indent@1.0.1: 1527 | resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} 1528 | engines: {node: '>=4'} 1529 | dev: true 1530 | 1531 | /minimatch@3.1.2: 1532 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1533 | dependencies: 1534 | brace-expansion: 1.1.11 1535 | dev: true 1536 | 1537 | /minimatch@5.1.6: 1538 | resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} 1539 | engines: {node: '>=10'} 1540 | dependencies: 1541 | brace-expansion: 2.0.1 1542 | dev: true 1543 | 1544 | /minimist@1.2.8: 1545 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 1546 | dev: true 1547 | 1548 | /mkdirp@0.5.6: 1549 | resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} 1550 | hasBin: true 1551 | dependencies: 1552 | minimist: 1.2.8 1553 | dev: true 1554 | 1555 | /mlly@1.4.2: 1556 | resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} 1557 | dependencies: 1558 | acorn: 8.11.2 1559 | pathe: 1.1.1 1560 | pkg-types: 1.0.3 1561 | ufo: 1.3.2 1562 | dev: true 1563 | 1564 | /mri@1.2.0: 1565 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 1566 | engines: {node: '>=4'} 1567 | dev: true 1568 | 1569 | /mrmime@1.0.1: 1570 | resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} 1571 | engines: {node: '>=10'} 1572 | dev: true 1573 | 1574 | /ms@2.1.2: 1575 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1576 | dev: true 1577 | 1578 | /nanoid@3.3.7: 1579 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 1580 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1581 | hasBin: true 1582 | dev: true 1583 | 1584 | /natural-compare@1.4.0: 1585 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1586 | dev: true 1587 | 1588 | /no-case@3.0.4: 1589 | resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} 1590 | dependencies: 1591 | lower-case: 2.0.2 1592 | tslib: 2.6.2 1593 | dev: true 1594 | 1595 | /normalize-path@3.0.0: 1596 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1597 | engines: {node: '>=0.10.0'} 1598 | dev: true 1599 | 1600 | /npm-bundled@2.0.1: 1601 | resolution: {integrity: sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==} 1602 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 1603 | dependencies: 1604 | npm-normalize-package-bin: 2.0.0 1605 | dev: true 1606 | 1607 | /npm-normalize-package-bin@2.0.0: 1608 | resolution: {integrity: sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==} 1609 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 1610 | dev: true 1611 | 1612 | /npm-packlist@5.1.3: 1613 | resolution: {integrity: sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==} 1614 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 1615 | hasBin: true 1616 | dependencies: 1617 | glob: 8.1.0 1618 | ignore-walk: 5.0.1 1619 | npm-bundled: 2.0.1 1620 | npm-normalize-package-bin: 2.0.0 1621 | dev: true 1622 | 1623 | /once@1.4.0: 1624 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1625 | dependencies: 1626 | wrappy: 1.0.2 1627 | dev: true 1628 | 1629 | /optionator@0.9.3: 1630 | resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} 1631 | engines: {node: '>= 0.8.0'} 1632 | dependencies: 1633 | '@aashutoshrathi/word-wrap': 1.2.6 1634 | deep-is: 0.1.4 1635 | fast-levenshtein: 2.0.6 1636 | levn: 0.4.1 1637 | prelude-ls: 1.2.1 1638 | type-check: 0.4.0 1639 | dev: true 1640 | 1641 | /p-limit@3.1.0: 1642 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1643 | engines: {node: '>=10'} 1644 | dependencies: 1645 | yocto-queue: 0.1.0 1646 | dev: true 1647 | 1648 | /p-limit@4.0.0: 1649 | resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} 1650 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1651 | dependencies: 1652 | yocto-queue: 1.0.0 1653 | dev: true 1654 | 1655 | /p-locate@5.0.0: 1656 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1657 | engines: {node: '>=10'} 1658 | dependencies: 1659 | p-limit: 3.1.0 1660 | dev: true 1661 | 1662 | /parent-module@1.0.1: 1663 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1664 | engines: {node: '>=6'} 1665 | dependencies: 1666 | callsites: 3.1.0 1667 | dev: true 1668 | 1669 | /pascal-case@3.1.2: 1670 | resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} 1671 | dependencies: 1672 | no-case: 3.0.4 1673 | tslib: 2.6.2 1674 | dev: true 1675 | 1676 | /path-exists@4.0.0: 1677 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1678 | engines: {node: '>=8'} 1679 | dev: true 1680 | 1681 | /path-is-absolute@1.0.1: 1682 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 1683 | engines: {node: '>=0.10.0'} 1684 | dev: true 1685 | 1686 | /path-key@3.1.1: 1687 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1688 | engines: {node: '>=8'} 1689 | dev: true 1690 | 1691 | /path-type@4.0.0: 1692 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 1693 | engines: {node: '>=8'} 1694 | dev: true 1695 | 1696 | /pathe@1.1.1: 1697 | resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} 1698 | dev: true 1699 | 1700 | /pathval@1.1.1: 1701 | resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} 1702 | dev: true 1703 | 1704 | /periscopic@3.1.0: 1705 | resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} 1706 | dependencies: 1707 | '@types/estree': 1.0.5 1708 | estree-walker: 3.0.3 1709 | is-reference: 3.0.2 1710 | dev: true 1711 | 1712 | /picocolors@1.0.0: 1713 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 1714 | dev: true 1715 | 1716 | /picomatch@2.3.1: 1717 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1718 | engines: {node: '>=8.6'} 1719 | dev: true 1720 | 1721 | /pkg-types@1.0.3: 1722 | resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} 1723 | dependencies: 1724 | jsonc-parser: 3.2.0 1725 | mlly: 1.4.2 1726 | pathe: 1.1.1 1727 | dev: true 1728 | 1729 | /postcss-load-config@3.1.4(postcss@8.4.31): 1730 | resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} 1731 | engines: {node: '>= 10'} 1732 | peerDependencies: 1733 | postcss: '>=8.0.9' 1734 | ts-node: '>=9.0.0' 1735 | peerDependenciesMeta: 1736 | postcss: 1737 | optional: true 1738 | ts-node: 1739 | optional: true 1740 | dependencies: 1741 | lilconfig: 2.1.0 1742 | postcss: 8.4.31 1743 | yaml: 1.10.2 1744 | dev: true 1745 | 1746 | /postcss-safe-parser@6.0.0(postcss@8.4.31): 1747 | resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} 1748 | engines: {node: '>=12.0'} 1749 | peerDependencies: 1750 | postcss: ^8.3.3 1751 | dependencies: 1752 | postcss: 8.4.31 1753 | dev: true 1754 | 1755 | /postcss-scss@4.0.9(postcss@8.4.31): 1756 | resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} 1757 | engines: {node: '>=12.0'} 1758 | peerDependencies: 1759 | postcss: ^8.4.29 1760 | dependencies: 1761 | postcss: 8.4.31 1762 | dev: true 1763 | 1764 | /postcss-selector-parser@6.0.13: 1765 | resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} 1766 | engines: {node: '>=4'} 1767 | dependencies: 1768 | cssesc: 3.0.0 1769 | util-deprecate: 1.0.2 1770 | dev: true 1771 | 1772 | /postcss@8.4.31: 1773 | resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} 1774 | engines: {node: ^10 || ^12 || >=14} 1775 | dependencies: 1776 | nanoid: 3.3.7 1777 | picocolors: 1.0.0 1778 | source-map-js: 1.0.2 1779 | dev: true 1780 | 1781 | /prelude-ls@1.2.1: 1782 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1783 | engines: {node: '>= 0.8.0'} 1784 | dev: true 1785 | 1786 | /prettier-plugin-svelte@3.1.2(prettier@3.1.0)(svelte@4.2.7): 1787 | resolution: {integrity: sha512-7xfMZtwgAWHMT0iZc8jN4o65zgbAQ3+O32V6W7pXrqNvKnHnkoyQCGCbKeUyXKZLbYE0YhFRnamfxfkEGxm8qA==} 1788 | peerDependencies: 1789 | prettier: ^3.0.0 1790 | svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 1791 | dependencies: 1792 | prettier: 3.1.0 1793 | svelte: 4.2.7 1794 | dev: true 1795 | 1796 | /prettier@3.1.0: 1797 | resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==} 1798 | engines: {node: '>=14'} 1799 | hasBin: true 1800 | dev: true 1801 | 1802 | /pretty-format@29.7.0: 1803 | resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} 1804 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1805 | dependencies: 1806 | '@jest/schemas': 29.6.3 1807 | ansi-styles: 5.2.0 1808 | react-is: 18.2.0 1809 | dev: true 1810 | 1811 | /publint@0.1.16: 1812 | resolution: {integrity: sha512-wJgk7HnXDT5Ap0DjFYbGz78kPkN44iQvDiaq8P63IEEyNU9mYXvaMd2cAyIM6OgqXM/IA3CK6XWIsRq+wjNpgw==} 1813 | engines: {node: '>=16'} 1814 | hasBin: true 1815 | dependencies: 1816 | npm-packlist: 5.1.3 1817 | picocolors: 1.0.0 1818 | sade: 1.8.1 1819 | dev: true 1820 | 1821 | /punycode@2.3.1: 1822 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1823 | engines: {node: '>=6'} 1824 | dev: true 1825 | 1826 | /queue-microtask@1.2.3: 1827 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1828 | dev: true 1829 | 1830 | /react-is@18.2.0: 1831 | resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} 1832 | dev: true 1833 | 1834 | /readdirp@3.6.0: 1835 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1836 | engines: {node: '>=8.10.0'} 1837 | dependencies: 1838 | picomatch: 2.3.1 1839 | dev: true 1840 | 1841 | /resolve-from@4.0.0: 1842 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1843 | engines: {node: '>=4'} 1844 | dev: true 1845 | 1846 | /reusify@1.0.4: 1847 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1848 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1849 | dev: true 1850 | 1851 | /rimraf@2.7.1: 1852 | resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} 1853 | hasBin: true 1854 | dependencies: 1855 | glob: 7.2.3 1856 | dev: true 1857 | 1858 | /rimraf@3.0.2: 1859 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1860 | hasBin: true 1861 | dependencies: 1862 | glob: 7.2.3 1863 | dev: true 1864 | 1865 | /rollup@3.29.4: 1866 | resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} 1867 | engines: {node: '>=14.18.0', npm: '>=8.0.0'} 1868 | hasBin: true 1869 | optionalDependencies: 1870 | fsevents: 2.3.3 1871 | dev: true 1872 | 1873 | /run-parallel@1.2.0: 1874 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1875 | dependencies: 1876 | queue-microtask: 1.2.3 1877 | dev: true 1878 | 1879 | /sade@1.8.1: 1880 | resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 1881 | engines: {node: '>=6'} 1882 | dependencies: 1883 | mri: 1.2.0 1884 | dev: true 1885 | 1886 | /sander@0.5.1: 1887 | resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} 1888 | dependencies: 1889 | es6-promise: 3.3.1 1890 | graceful-fs: 4.2.11 1891 | mkdirp: 0.5.6 1892 | rimraf: 2.7.1 1893 | dev: true 1894 | 1895 | /semver@7.5.4: 1896 | resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} 1897 | engines: {node: '>=10'} 1898 | hasBin: true 1899 | dependencies: 1900 | lru-cache: 6.0.0 1901 | dev: true 1902 | 1903 | /set-cookie-parser@2.6.0: 1904 | resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} 1905 | dev: true 1906 | 1907 | /shebang-command@2.0.0: 1908 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1909 | engines: {node: '>=8'} 1910 | dependencies: 1911 | shebang-regex: 3.0.0 1912 | dev: true 1913 | 1914 | /shebang-regex@3.0.0: 1915 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1916 | engines: {node: '>=8'} 1917 | dev: true 1918 | 1919 | /siginfo@2.0.0: 1920 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 1921 | dev: true 1922 | 1923 | /sirv@2.0.3: 1924 | resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} 1925 | engines: {node: '>= 10'} 1926 | dependencies: 1927 | '@polka/url': 1.0.0-next.23 1928 | mrmime: 1.0.1 1929 | totalist: 3.0.1 1930 | dev: true 1931 | 1932 | /slash@3.0.0: 1933 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 1934 | engines: {node: '>=8'} 1935 | dev: true 1936 | 1937 | /sorcery@0.11.0: 1938 | resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==} 1939 | hasBin: true 1940 | dependencies: 1941 | '@jridgewell/sourcemap-codec': 1.4.15 1942 | buffer-crc32: 0.2.13 1943 | minimist: 1.2.8 1944 | sander: 0.5.1 1945 | dev: true 1946 | 1947 | /source-map-js@1.0.2: 1948 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 1949 | engines: {node: '>=0.10.0'} 1950 | dev: true 1951 | 1952 | /stackback@0.0.2: 1953 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 1954 | dev: true 1955 | 1956 | /std-env@3.5.0: 1957 | resolution: {integrity: sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA==} 1958 | dev: true 1959 | 1960 | /strip-ansi@6.0.1: 1961 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1962 | engines: {node: '>=8'} 1963 | dependencies: 1964 | ansi-regex: 5.0.1 1965 | dev: true 1966 | 1967 | /strip-indent@3.0.0: 1968 | resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} 1969 | engines: {node: '>=8'} 1970 | dependencies: 1971 | min-indent: 1.0.1 1972 | dev: true 1973 | 1974 | /strip-json-comments@3.1.1: 1975 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1976 | engines: {node: '>=8'} 1977 | dev: true 1978 | 1979 | /strip-literal@1.3.0: 1980 | resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==} 1981 | dependencies: 1982 | acorn: 8.11.2 1983 | dev: true 1984 | 1985 | /supports-color@7.2.0: 1986 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1987 | engines: {node: '>=8'} 1988 | dependencies: 1989 | has-flag: 4.0.0 1990 | dev: true 1991 | 1992 | /svelte-check@3.6.2(postcss@8.4.31)(svelte@4.2.7): 1993 | resolution: {integrity: sha512-E6iFh4aUCGJLRz6QZXH3gcN/VFfkzwtruWSRmlKrLWQTiO6VzLsivR6q02WYLGNAGecV3EocqZuCDrC2uttZ0g==} 1994 | hasBin: true 1995 | peerDependencies: 1996 | svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 1997 | dependencies: 1998 | '@jridgewell/trace-mapping': 0.3.20 1999 | chokidar: 3.5.3 2000 | fast-glob: 3.3.2 2001 | import-fresh: 3.3.0 2002 | picocolors: 1.0.0 2003 | sade: 1.8.1 2004 | svelte: 4.2.7 2005 | svelte-preprocess: 5.1.1(postcss@8.4.31)(svelte@4.2.7)(typescript@5.3.2) 2006 | typescript: 5.3.2 2007 | transitivePeerDependencies: 2008 | - '@babel/core' 2009 | - coffeescript 2010 | - less 2011 | - postcss 2012 | - postcss-load-config 2013 | - pug 2014 | - sass 2015 | - stylus 2016 | - sugarss 2017 | dev: true 2018 | 2019 | /svelte-eslint-parser@0.33.1(svelte@4.2.7): 2020 | resolution: {integrity: sha512-vo7xPGTlKBGdLH8T5L64FipvTrqv3OQRx9d2z5X05KKZDlF4rQk8KViZO4flKERY+5BiVdOh7zZ7JGJWo5P0uA==} 2021 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 2022 | peerDependencies: 2023 | svelte: ^3.37.0 || ^4.0.0 2024 | peerDependenciesMeta: 2025 | svelte: 2026 | optional: true 2027 | dependencies: 2028 | eslint-scope: 7.2.2 2029 | eslint-visitor-keys: 3.4.3 2030 | espree: 9.6.1 2031 | postcss: 8.4.31 2032 | postcss-scss: 4.0.9(postcss@8.4.31) 2033 | svelte: 4.2.7 2034 | dev: true 2035 | 2036 | /svelte-hmr@0.15.3(svelte@4.2.7): 2037 | resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==} 2038 | engines: {node: ^12.20 || ^14.13.1 || >= 16} 2039 | peerDependencies: 2040 | svelte: ^3.19.0 || ^4.0.0 2041 | dependencies: 2042 | svelte: 4.2.7 2043 | dev: true 2044 | 2045 | /svelte-preprocess@5.1.1(postcss@8.4.31)(svelte@4.2.7)(typescript@5.3.2): 2046 | resolution: {integrity: sha512-p/Dp4hmrBW5mrCCq29lEMFpIJT2FZsRlouxEc5qpbOmXRbaFs7clLs8oKPwD3xCFyZfv1bIhvOzpQkhMEVQdMw==} 2047 | engines: {node: '>= 14.10.0'} 2048 | requiresBuild: true 2049 | peerDependencies: 2050 | '@babel/core': ^7.10.2 2051 | coffeescript: ^2.5.1 2052 | less: ^3.11.3 || ^4.0.0 2053 | postcss: ^7 || ^8 2054 | postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 2055 | pug: ^3.0.0 2056 | sass: ^1.26.8 2057 | stylus: ^0.55.0 2058 | sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0 2059 | svelte: ^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 2060 | typescript: '>=3.9.5 || ^4.0.0 || ^5.0.0' 2061 | peerDependenciesMeta: 2062 | '@babel/core': 2063 | optional: true 2064 | coffeescript: 2065 | optional: true 2066 | less: 2067 | optional: true 2068 | postcss: 2069 | optional: true 2070 | postcss-load-config: 2071 | optional: true 2072 | pug: 2073 | optional: true 2074 | sass: 2075 | optional: true 2076 | stylus: 2077 | optional: true 2078 | sugarss: 2079 | optional: true 2080 | typescript: 2081 | optional: true 2082 | dependencies: 2083 | '@types/pug': 2.0.10 2084 | detect-indent: 6.1.0 2085 | magic-string: 0.27.0 2086 | postcss: 8.4.31 2087 | sorcery: 0.11.0 2088 | strip-indent: 3.0.0 2089 | svelte: 4.2.7 2090 | typescript: 5.3.2 2091 | dev: true 2092 | 2093 | /svelte2tsx@0.6.27(svelte@4.2.7)(typescript@5.3.2): 2094 | resolution: {integrity: sha512-E1uPW1o6VsbRz+nUk3fznZ2lSmCITAJoNu8AYefWSvIwE2pSB01i5sId4RMbWNzfcwCQl1DcgGShCPcldl4rvg==} 2095 | peerDependencies: 2096 | svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 2097 | typescript: ^4.9.4 || ^5.0.0 2098 | dependencies: 2099 | dedent-js: 1.0.1 2100 | pascal-case: 3.1.2 2101 | svelte: 4.2.7 2102 | typescript: 5.3.2 2103 | dev: true 2104 | 2105 | /svelte@4.2.7: 2106 | resolution: {integrity: sha512-UExR1KS7raTdycsUrKLtStayu4hpdV3VZQgM0akX8XbXgLBlosdE/Sf3crOgyh9xIjqSYB3UEBuUlIQKRQX2hg==} 2107 | engines: {node: '>=16'} 2108 | dependencies: 2109 | '@ampproject/remapping': 2.2.1 2110 | '@jridgewell/sourcemap-codec': 1.4.15 2111 | '@jridgewell/trace-mapping': 0.3.20 2112 | acorn: 8.11.2 2113 | aria-query: 5.3.0 2114 | axobject-query: 3.2.1 2115 | code-red: 1.0.4 2116 | css-tree: 2.3.1 2117 | estree-walker: 3.0.3 2118 | is-reference: 3.0.2 2119 | locate-character: 3.0.0 2120 | magic-string: 0.30.5 2121 | periscopic: 3.1.0 2122 | dev: true 2123 | 2124 | /text-table@0.2.0: 2125 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 2126 | dev: true 2127 | 2128 | /tiny-glob@0.2.9: 2129 | resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} 2130 | dependencies: 2131 | globalyzer: 0.1.0 2132 | globrex: 0.1.2 2133 | dev: true 2134 | 2135 | /tinybench@2.5.1: 2136 | resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==} 2137 | dev: true 2138 | 2139 | /tinypool@0.7.0: 2140 | resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==} 2141 | engines: {node: '>=14.0.0'} 2142 | dev: true 2143 | 2144 | /tinyspy@2.2.0: 2145 | resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} 2146 | engines: {node: '>=14.0.0'} 2147 | dev: true 2148 | 2149 | /to-regex-range@5.0.1: 2150 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 2151 | engines: {node: '>=8.0'} 2152 | dependencies: 2153 | is-number: 7.0.0 2154 | dev: true 2155 | 2156 | /totalist@3.0.1: 2157 | resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 2158 | engines: {node: '>=6'} 2159 | dev: true 2160 | 2161 | /ts-api-utils@1.0.3(typescript@5.3.2): 2162 | resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} 2163 | engines: {node: '>=16.13.0'} 2164 | peerDependencies: 2165 | typescript: '>=4.2.0' 2166 | dependencies: 2167 | typescript: 5.3.2 2168 | dev: true 2169 | 2170 | /tslib@2.6.2: 2171 | resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} 2172 | dev: true 2173 | 2174 | /type-check@0.4.0: 2175 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 2176 | engines: {node: '>= 0.8.0'} 2177 | dependencies: 2178 | prelude-ls: 1.2.1 2179 | dev: true 2180 | 2181 | /type-detect@4.0.8: 2182 | resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} 2183 | engines: {node: '>=4'} 2184 | dev: true 2185 | 2186 | /type-fest@0.20.2: 2187 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} 2188 | engines: {node: '>=10'} 2189 | dev: true 2190 | 2191 | /typescript@5.3.2: 2192 | resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} 2193 | engines: {node: '>=14.17'} 2194 | hasBin: true 2195 | dev: true 2196 | 2197 | /ufo@1.3.2: 2198 | resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} 2199 | dev: true 2200 | 2201 | /undici-types@5.26.5: 2202 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 2203 | dev: true 2204 | 2205 | /undici@5.26.5: 2206 | resolution: {integrity: sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==} 2207 | engines: {node: '>=14.0'} 2208 | dependencies: 2209 | '@fastify/busboy': 2.1.0 2210 | dev: true 2211 | 2212 | /uri-js@4.4.1: 2213 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 2214 | dependencies: 2215 | punycode: 2.3.1 2216 | dev: true 2217 | 2218 | /util-deprecate@1.0.2: 2219 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 2220 | dev: true 2221 | 2222 | /vite-node@0.34.6(@types/node@20.10.0): 2223 | resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} 2224 | engines: {node: '>=v14.18.0'} 2225 | hasBin: true 2226 | dependencies: 2227 | cac: 6.7.14 2228 | debug: 4.3.4 2229 | mlly: 1.4.2 2230 | pathe: 1.1.1 2231 | picocolors: 1.0.0 2232 | vite: 4.5.0(@types/node@20.10.0) 2233 | transitivePeerDependencies: 2234 | - '@types/node' 2235 | - less 2236 | - lightningcss 2237 | - sass 2238 | - stylus 2239 | - sugarss 2240 | - supports-color 2241 | - terser 2242 | dev: true 2243 | 2244 | /vite@4.5.0(@types/node@20.10.0): 2245 | resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} 2246 | engines: {node: ^14.18.0 || >=16.0.0} 2247 | hasBin: true 2248 | peerDependencies: 2249 | '@types/node': '>= 14' 2250 | less: '*' 2251 | lightningcss: ^1.21.0 2252 | sass: '*' 2253 | stylus: '*' 2254 | sugarss: '*' 2255 | terser: ^5.4.0 2256 | peerDependenciesMeta: 2257 | '@types/node': 2258 | optional: true 2259 | less: 2260 | optional: true 2261 | lightningcss: 2262 | optional: true 2263 | sass: 2264 | optional: true 2265 | stylus: 2266 | optional: true 2267 | sugarss: 2268 | optional: true 2269 | terser: 2270 | optional: true 2271 | dependencies: 2272 | '@types/node': 20.10.0 2273 | esbuild: 0.18.20 2274 | postcss: 8.4.31 2275 | rollup: 3.29.4 2276 | optionalDependencies: 2277 | fsevents: 2.3.3 2278 | dev: true 2279 | 2280 | /vitefu@0.2.5(vite@4.5.0): 2281 | resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} 2282 | peerDependencies: 2283 | vite: ^3.0.0 || ^4.0.0 || ^5.0.0 2284 | peerDependenciesMeta: 2285 | vite: 2286 | optional: true 2287 | dependencies: 2288 | vite: 4.5.0(@types/node@20.10.0) 2289 | dev: true 2290 | 2291 | /vitest@0.34.6: 2292 | resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} 2293 | engines: {node: '>=v14.18.0'} 2294 | hasBin: true 2295 | peerDependencies: 2296 | '@edge-runtime/vm': '*' 2297 | '@vitest/browser': '*' 2298 | '@vitest/ui': '*' 2299 | happy-dom: '*' 2300 | jsdom: '*' 2301 | playwright: '*' 2302 | safaridriver: '*' 2303 | webdriverio: '*' 2304 | peerDependenciesMeta: 2305 | '@edge-runtime/vm': 2306 | optional: true 2307 | '@vitest/browser': 2308 | optional: true 2309 | '@vitest/ui': 2310 | optional: true 2311 | happy-dom: 2312 | optional: true 2313 | jsdom: 2314 | optional: true 2315 | playwright: 2316 | optional: true 2317 | safaridriver: 2318 | optional: true 2319 | webdriverio: 2320 | optional: true 2321 | dependencies: 2322 | '@types/chai': 4.3.11 2323 | '@types/chai-subset': 1.3.5 2324 | '@types/node': 20.10.0 2325 | '@vitest/expect': 0.34.6 2326 | '@vitest/runner': 0.34.6 2327 | '@vitest/snapshot': 0.34.6 2328 | '@vitest/spy': 0.34.6 2329 | '@vitest/utils': 0.34.6 2330 | acorn: 8.11.2 2331 | acorn-walk: 8.3.0 2332 | cac: 6.7.14 2333 | chai: 4.3.10 2334 | debug: 4.3.4 2335 | local-pkg: 0.4.3 2336 | magic-string: 0.30.5 2337 | pathe: 1.1.1 2338 | picocolors: 1.0.0 2339 | std-env: 3.5.0 2340 | strip-literal: 1.3.0 2341 | tinybench: 2.5.1 2342 | tinypool: 0.7.0 2343 | vite: 4.5.0(@types/node@20.10.0) 2344 | vite-node: 0.34.6(@types/node@20.10.0) 2345 | why-is-node-running: 2.2.2 2346 | transitivePeerDependencies: 2347 | - less 2348 | - lightningcss 2349 | - sass 2350 | - stylus 2351 | - sugarss 2352 | - supports-color 2353 | - terser 2354 | dev: true 2355 | 2356 | /which@2.0.2: 2357 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 2358 | engines: {node: '>= 8'} 2359 | hasBin: true 2360 | dependencies: 2361 | isexe: 2.0.0 2362 | dev: true 2363 | 2364 | /why-is-node-running@2.2.2: 2365 | resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} 2366 | engines: {node: '>=8'} 2367 | hasBin: true 2368 | dependencies: 2369 | siginfo: 2.0.0 2370 | stackback: 0.0.2 2371 | dev: true 2372 | 2373 | /wrappy@1.0.2: 2374 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 2375 | dev: true 2376 | 2377 | /yallist@4.0.0: 2378 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 2379 | dev: true 2380 | 2381 | /yaml@1.10.2: 2382 | resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} 2383 | engines: {node: '>= 6'} 2384 | dev: true 2385 | 2386 | /yocto-queue@0.1.0: 2387 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 2388 | engines: {node: '>=10'} 2389 | dev: true 2390 | 2391 | /yocto-queue@1.0.0: 2392 | resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} 2393 | engines: {node: '>=12.20'} 2394 | dev: true 2395 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 13 | 14 | %sveltekit.head% 15 | 16 | 17 |
%sveltekit.body%
18 | 19 | 20 | -------------------------------------------------------------------------------- /src/lib/db.ts: -------------------------------------------------------------------------------- 1 | // Simple mock database for testing purposes 2 | export const db = { 3 | articles: [ 4 | { 5 | id: 1, 6 | title: 'The article title' 7 | }, 8 | { 9 | id: 2, 10 | title: 'Another article' 11 | }, 12 | { 13 | id: 3, 14 | title: 'third' 15 | }, 16 | { 17 | id: 123, 18 | title: '' // testing empty string too 19 | }, 20 | { 21 | id: 4, 22 | title: 'Why did the chicken cross the road?? And more!' 23 | } 24 | ] 25 | }; 26 | -------------------------------------------------------------------------------- /src/lib/identifier-handlers/hyphen-identifier-handler.ts: -------------------------------------------------------------------------------- 1 | import type { IdentifierHandler } from '$lib/types/index.js'; 2 | 3 | /** 4 | * Implementation of the IdentifierHandler interface that uses hyphens to separate the slug from the identifier 5 | */ 6 | export const HyphenIdentifierHandler: IdentifierHandler = { 7 | join: (slug, identifier) => { 8 | // Handle edge case so we dont try to redirect to "/-123" which would break the parser 9 | if (slug === '') return `${identifier}`; 10 | return `${slug}-${identifier}`; 11 | }, 12 | separate: (slug) => { 13 | const [identifier, ...rest] = slug.split('-').reverse(); 14 | return { 15 | identifier, 16 | slug: rest.reverse().join('-') 17 | }; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { HyphenIdentifierHandler } from './identifier-handlers/hyphen-identifier-handler.js'; 2 | import { NamedComparator } from './route-comparators/named-comparator.js'; 3 | import { KebabSlugSanitizer } from './slug-sanitizers/kebab-slug-sanitizer.js'; 4 | import type { 5 | Selfhealer, 6 | SelfhealerConfig, 7 | UrlCreator, 8 | UrlIdParser, 9 | UrlValidator 10 | } from './types/index.js'; 11 | 12 | /** 13 | * Returns a `Selfhealer` with the default configuration 14 | * - slugSanitizer: `KebabSlugSanitizer` 15 | * - comparator: `NamedComparator` 16 | * - identifierHandler: `HyphenIdentifierHandler` 17 | * @param params Parameters to override the default configuration 18 | * @returns An object containing the required functions to handle URL self-healing 19 | */ 20 | export const selfheal = (params?: SelfhealerConfig): Selfhealer => { 21 | const healer: SelfhealerConfig = { 22 | sanitize: params?.sanitize ?? KebabSlugSanitizer, 23 | isEqual: params?.isEqual ?? NamedComparator, 24 | identifier: params?.identifier ?? HyphenIdentifierHandler 25 | }; 26 | 27 | const createUrl: UrlCreator = (identifier, slug, params) => { 28 | let redirectUrl = healer.identifier.join(healer.sanitize(slug), identifier); 29 | 30 | if (params && params.size > 0) redirectUrl += `?${params.toString()}`; 31 | 32 | return redirectUrl; 33 | }; 34 | 35 | const parseId: UrlIdParser = (slug) => { 36 | return healer.identifier.separate(slug).identifier; 37 | }; 38 | 39 | const validate: UrlValidator = (expectedUrl, actualRoute, params) => { 40 | if (params && params.size > 0) actualRoute += `?${params.toString()}`; 41 | return healer.isEqual(expectedUrl, actualRoute); 42 | }; 43 | 44 | return { 45 | parseId, 46 | createUrl, 47 | validate 48 | }; 49 | }; 50 | -------------------------------------------------------------------------------- /src/lib/route-comparators/named-comparator.ts: -------------------------------------------------------------------------------- 1 | import type { RouteComparator } from '$lib/types/index.js'; 2 | 3 | /** 4 | * Implementation of the `RouteComparator` interface that simply compares both arguments using strict equality `===` 5 | * 6 | * @param expected The expected value as generated from the database sanitization 7 | * @param actual The actual slug value from the url 8 | * @returns `true` if the values are equal **as specified by the implementation**, `false` if they are unequal 9 | */ 10 | export const NamedComparator: RouteComparator = (expected, actual) => { 11 | return expected === actual; 12 | }; 13 | -------------------------------------------------------------------------------- /src/lib/selfheal.ts: -------------------------------------------------------------------------------- 1 | import { selfheal } from './index.js'; 2 | 3 | export const healer = selfheal(); 4 | -------------------------------------------------------------------------------- /src/lib/slug-sanitizers/kebab-slug-sanitizer.ts: -------------------------------------------------------------------------------- 1 | import type { SlugSanitizer } from '$lib/types/index.js'; 2 | 3 | /** 4 | * Replaces spaces with hyphens, removes multiple hyphens, removes hyphens at the start and end of the string 5 | * @param slug The slug to sanitize 6 | * @returns The sanitized slug 7 | */ 8 | export const KebabSlugSanitizer: SlugSanitizer = (slug) => { 9 | const options = { condense: true }; // TODO make this passable through dynamic params 10 | return slug 11 | .trim() 12 | .replace(/([a-z])([A-Z])/g, '$1-$2') 13 | .replace(/\W/g, (m) => (/[À-ž]/.test(m) ? m : '-')) 14 | .replace(/^-+|-+$/g, '') 15 | .replace(/-{2,}/g, (m) => (options && options.condense ? '-' : m)) 16 | .toLowerCase(); 17 | }; 18 | -------------------------------------------------------------------------------- /src/lib/types/index.ts: -------------------------------------------------------------------------------- 1 | export type SlugSanitizer = ( 2 | slug: string 3 | /* 4 | TODO add interface for options so implementations can specify their own options 5 | options?: Record 6 | */ 7 | ) => string; 8 | 9 | export type IdentifierHandler = { 10 | /** 11 | * Joins the slug with the identifier as specified during initialization and returns the new slug 12 | * @param slug The slug to join 13 | * @param identifier The identifier to join to the slug 14 | * @returns The complete url slug 15 | */ 16 | join: (slug: string, identifier: string | number) => string; 17 | /** 18 | * Separates the actual identifier from the slug and returns an object containing both 19 | * @param slug The slug to separate 20 | * @returns An object containing the `identifier` and the slug, which **may be empty** if only the ID was used during the request! 21 | */ 22 | separate: (slug: string) => { identifier: string; slug: string }; 23 | }; 24 | 25 | export type UrlIdParser = (slug: string) => string; 26 | 27 | export type UrlCreator = ( 28 | identifier: string | number, 29 | slug: string, 30 | searchParams?: URLSearchParams 31 | ) => string; 32 | 33 | export type UrlValidator = ( 34 | expectedUrl: string, 35 | actualRoute: string, 36 | params?: URLSearchParams 37 | ) => boolean; 38 | 39 | export type RouteComparator = (expectedValue: string, actualValue: string) => boolean; 40 | 41 | export type SelfhealerConfig = { 42 | /** 43 | * Given the desired URL slug (e.g. an article title), returns a usable sanitized string for the URL 44 | */ 45 | sanitize: SlugSanitizer; 46 | /** 47 | * Given the expected and actual routes, returns `true` if the arguments are equal, `false` otherwise 48 | */ 49 | isEqual: RouteComparator; 50 | /** 51 | * Handles joining and separating slugs with/from the actual identifiers 52 | */ 53 | identifier: IdentifierHandler; 54 | }; 55 | 56 | export type Selfhealer = { 57 | /** 58 | * Parse the identifier from the *current* route parameter 59 | * @param slug The ID coming from the `params` object in the load function 60 | * @returns The identifier to use for the database lookup 61 | */ 62 | parseId: UrlIdParser; 63 | /** 64 | * Checks if the expected url matches the actual url using the `RedirectChecker` specified during initialization 65 | * @param expectedUrl The expected canonical URL 66 | * @param actualRoute The actual *route* (not the full url) the user is on 67 | * @param params The search params to append to the current route so it can be compared to the canonical URL, if any 68 | * @returns `true` if the values are equal **as specified by the implementation**, `false` if they are unequal 69 | */ 70 | validate: UrlValidator; 71 | /** 72 | * Sanitizes the slug and joins it with the identifier 73 | * @param slug The slug to sanitize and join with the identifier 74 | * @param identifier The actual resource identifier 75 | * @param searchParams The search params to append to the url, if any 76 | * @returns A new slug with the identifier appended in the way you specified in the selfheal configuration 77 | */ 78 | createUrl: UrlCreator; 79 | }; 80 | -------------------------------------------------------------------------------- /src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |

Articles

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {#each data.articles as { id, title }} 18 | 19 | 20 | 21 | 26 | 29 | 30 | {/each} 31 | 32 |
IDTitleSEO friendly URLID URL
{id}{title} 22 | 23 | /{healer.createUrl(id, title)} 24 | 25 | 27 | /{id} 28 |
33 | -------------------------------------------------------------------------------- /src/routes/+page.ts: -------------------------------------------------------------------------------- 1 | import { db } from '$lib/db.js'; 2 | import type { PageLoad } from './$types.js'; 3 | 4 | export const load = (async () => { 5 | return { 6 | articles: db.articles 7 | }; 8 | }) satisfies PageLoad; 9 | -------------------------------------------------------------------------------- /src/routes/[id]/+error.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |

Error {$page.status}

7 |

{$page.error?.message}

8 |
9 | -------------------------------------------------------------------------------- /src/routes/[id]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { db } from '$lib/db.js'; 2 | import { healer } from '$lib/selfheal.js'; 3 | import { error, redirect } from '@sveltejs/kit'; 4 | import type { PageServerLoad } from './$types.js'; 5 | 6 | export const load: PageServerLoad = async ({ params, url }) => { 7 | const identifier = healer.parseId(params.id); 8 | 9 | const article = db.articles.find((article) => String(article.id) === identifier); 10 | if (!article) throw error(404, `Article "${identifier}" not found`); 11 | 12 | const expectedUrl = healer.createUrl(article.id, article.title, url.searchParams); 13 | const valid = healer.validate(expectedUrl, params.id, url.searchParams); 14 | if (!valid) throw redirect(301, expectedUrl); 15 | 16 | return { article, slug: params.id }; 17 | }; 18 | -------------------------------------------------------------------------------- /src/routes/[id]/+page.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | Home 6 | 7 |

{data.slug}

8 | 9 |
{JSON.stringify(data.article, null, 4)}
10 | 11 |

12 | You can change or remove the URL before the ID ({data.article.id}) and the page should 13 | still load. 14 |

15 | 16 | Go deeper 17 | -------------------------------------------------------------------------------- /src/routes/[id]/details/+page.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 | You have reached the details page! 5 | -------------------------------------------------------------------------------- /src/routes/[id]/details/[innerId]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import type { PageServerLoad } from './$types.js'; 2 | import { healer } from '$lib/selfheal.js'; 3 | import { error, redirect } from '@sveltejs/kit'; 4 | import { db } from '$lib/db.js'; 5 | 6 | export const load: PageServerLoad = async ({ params, url }) => { 7 | const identifier = healer.parseId(params.innerId); 8 | 9 | const article = db.articles.find((article) => String(article.id) === identifier); 10 | if (!article) throw error(404, `Article "${identifier}" not found`); 11 | 12 | const expectedUrl = healer.createUrl(article.id, article.title, url.searchParams); 13 | 14 | const valid = healer.validate(expectedUrl, params.innerId, url.searchParams); 15 | if (!valid) throw redirect(301, expectedUrl); 16 | 17 | return { article, slug: params.innerId }; 18 | }; 19 | -------------------------------------------------------------------------------- /src/routes/[id]/details/[innerId]/+page.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | Home 6 | 7 |

Inner details of {data.slug}

8 | 9 |
{JSON.stringify(data.article, null, 4)}
10 | 11 |

12 | You can change or remove the URL before the ID ({data.article.id}) and the page should 13 | still load. 14 |

15 |

16 | Note, however, that changing the parent slug will not heal that part of the URL as there is 17 | currently no clean way (that I know) to "listen" to that and invalidate it without checking on 18 | every nested child request, which is likely wasted performance and sacrifices loading time for 19 | little gains. 20 |

21 | -------------------------------------------------------------------------------- /src/tests/identifier-handlers/hyphen-identifier-handler.test.ts: -------------------------------------------------------------------------------- 1 | import { HyphenIdentifierHandler } from '$lib/identifier-handlers/hyphen-identifier-handler.js'; 2 | import { describe, expect, it } from 'vitest'; 3 | 4 | describe('HyphenIdentifierHandler', () => { 5 | it('adds a hyphen between the slug and identifier', () => { 6 | const slug = 'any-given-slug'; 7 | const identifier = '123'; 8 | expect(HyphenIdentifierHandler.join(slug, identifier)).toBe('any-given-slug-123'); 9 | }); 10 | 11 | it('separates the slug from the identifier', () => { 12 | const slug = 'any-given-slug-123'; 13 | expect(HyphenIdentifierHandler.separate(slug)).toEqual({ 14 | identifier: '123', 15 | slug: 'any-given-slug' 16 | }); 17 | }); 18 | 19 | it('returns only the ID if the slug is empty', () => { 20 | const slug = ''; 21 | const identifier = '123'; 22 | expect(HyphenIdentifierHandler.join(slug, identifier)).toBe('123'); 23 | }); 24 | 25 | 26 | it('handles multiple hyphens in the slug when separating', () => { 27 | const slug = 'multiple-hyphen-test-identifier'; 28 | expect(HyphenIdentifierHandler.separate(slug)).toEqual({ 29 | identifier: 'identifier', 30 | slug: 'multiple-hyphen-test' 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/tests/route-comparators/named-comparator.test.ts: -------------------------------------------------------------------------------- 1 | import { NamedComparator } from '$lib/route-comparators/named-comparator.js'; 2 | import { describe, expect, it } from 'vitest'; 3 | 4 | describe('NamedComparator', () => { 5 | it.each([ 6 | { 7 | description: 'returns true because both values are the same object', 8 | input: ['any-given-slug-123', 'any-given-slug-123'], 9 | expected: true, 10 | }, 11 | { 12 | description: 'returns false because values are unequal using ===', 13 | input: ['any-given-slug-123', 'any-given-slug-456'], 14 | expected: false, 15 | }, 16 | { 17 | description: 'returns false because the named comparator simply checks for equality of the strings', 18 | input: ['any-given-slug-123', 'any-given-slug-123?foo=bar'], 19 | expected: false, 20 | }, 21 | ])('%s', ({ input, expected }: { input: string[], expected: boolean }) => { 22 | const [a, b] = input; 23 | expect(NamedComparator(a, b)).toBe(expected); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/tests/slug-sanitizers/kebab-slug-sanitizer.test.ts: -------------------------------------------------------------------------------- 1 | import { KebabSlugSanitizer } from '$lib/slug-sanitizers/kebab-slug-sanitizer.js'; 2 | import { describe, expect, it } from 'vitest'; 3 | 4 | describe('KebabSlugSanitizer', () => { 5 | it('makes the slug lowercase', () => { 6 | const slug = 'AN UPPERCASE SLUG'; 7 | expect(KebabSlugSanitizer(slug)).toBe('an-uppercase-slug'); 8 | }); 9 | 10 | it('removes non-alphanumeric characters', () => { 11 | const badCharacters = [ 12 | '!', 13 | '@', 14 | '#', 15 | '$', 16 | '%', 17 | '^', 18 | '&', 19 | '*', 20 | '(', 21 | ')', 22 | '=', 23 | '+', 24 | '[', 25 | ']', 26 | '{', 27 | '}', 28 | '|', 29 | '\\', 30 | '/', 31 | '<', 32 | '>', 33 | '?', 34 | ',', 35 | '.', 36 | '`', 37 | '~', 38 | "'", 39 | '"', 40 | ';', 41 | ':', 42 | ]; 43 | 44 | badCharacters.forEach((char) => { 45 | it(`removes ${char}`, () => { 46 | expect(KebabSlugSanitizer(char)).toBe(''); 47 | }); 48 | }); 49 | }); 50 | 51 | it('replaces spaces with hyphens and removes multiple hyphens', () => { 52 | const testCases = [ 53 | { input: 'any given slug', expected: 'any-given-slug' }, 54 | { input: 'any--given------slug-123', expected: 'any-given-slug-123' }, 55 | { input: '-any-given-slug-', expected: 'any-given-slug' }, 56 | ]; 57 | 58 | testCases.forEach(({ input, expected }) => { 59 | it(`transforms "${input}" correctly`, () => { 60 | expect(KebabSlugSanitizer(input)).toBe(expected); 61 | }); 62 | }); 63 | }); 64 | 65 | it('handles special characters and accents', () => { 66 | const testCases = [ 67 | { input: 'cliché café', expected: 'cliche-cafe' }, 68 | { input: 'mötörhëäd', expected: 'motorhead' }, 69 | ]; 70 | 71 | testCases.forEach(({ input, expected }) => { 72 | it(`transforms "${input}" correctly`, () => { 73 | expect(KebabSlugSanitizer(input)).toBe(expected); 74 | }); 75 | }); 76 | }); 77 | 78 | it('handles edge cases', () => { 79 | const testCases = [ 80 | { input: '', expected: '' }, // Empty string 81 | { input: ' leading-trailing-whitespaces ', expected: 'leading-trailing-whitespaces' }, 82 | { input: '___underscores___', expected: 'underscores' }, 83 | { input: ' multiple spaces ', expected: 'multiple-spaces' }, 84 | ]; 85 | 86 | testCases.forEach(({ input, expected }) => { 87 | it(`transforms "${input}" correctly`, () => { 88 | expect(KebabSlugSanitizer(input)).toBe(expected); 89 | }); 90 | }); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /src/tests/usage.test.ts: -------------------------------------------------------------------------------- 1 | import { selfheal } from '$lib/index.js'; 2 | import { describe, expect, it } from 'vitest'; 3 | 4 | // Init a healer using the default configuration 5 | const healer = selfheal(); 6 | 7 | describe('URL creator', () => { 8 | it('sanitizes the slug and joins it with the identifier', () => { 9 | const slug = 'An unformatted SLUG'; 10 | const identifier = '123'; 11 | expect(healer.createUrl(identifier, slug)).toBe('an-unformatted-slug-123'); 12 | }); 13 | 14 | it('appends any given search params to the URL', () => { 15 | const slug = 'An unformatted SLUG'; 16 | const identifier = '123'; 17 | const params = new URLSearchParams({ test: 'true', numbers: '999' }); 18 | 19 | expect(healer.createUrl(identifier, slug, params)).toBe( 20 | 'an-unformatted-slug-123?test=true&numbers=999' 21 | ); 22 | }); 23 | 24 | it('handles default configuration if no parameters are provided', () => { 25 | const slug = 'An unformatted SLUG'; 26 | const identifier = '123'; 27 | expect(healer.createUrl(identifier, slug)).toBe('an-unformatted-slug-123'); 28 | }); 29 | 30 | it('handles default configuration if only slug and identifier are provided', () => { 31 | const slug = 'An unformatted SLUG'; 32 | const identifier = '123'; 33 | expect(healer.createUrl(identifier, slug)).toBe('an-unformatted-slug-123'); 34 | }); 35 | }); 36 | 37 | describe('URL parseId helper', () => { 38 | it('helper returns the correct identifier from the URL', () => { 39 | expect(healer.parseId('an-unformatted-slug-123')).toBe('123'); 40 | }); 41 | 42 | it('handles default configuration if only slug is provided', () => { 43 | const slug = 'an-unformatted-slug-123'; 44 | expect(healer.parseId(slug)).toBe('123'); 45 | }); 46 | 47 | it('handles default configuration if empty slug is provided', () => { 48 | const slug = ''; 49 | expect(healer.parseId(slug)).toBe(''); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dominic-schmid/svelte-selfheal/5cd0438bb43115e486acd3e89499932b6c3b035c/static/favicon.png -------------------------------------------------------------------------------- /static/svelte-selfheal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dominic-schmid/svelte-selfheal/5cd0438bb43115e486acd3e89499932b6c3b035c/static/svelte-selfheal.gif -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/kit/vite'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "module": "NodeNext", 13 | "moduleResolution": "NodeNext" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | test: { 7 | include: ['src/**/*.{test,spec}.{js,ts}'] 8 | } 9 | }); 10 | --------------------------------------------------------------------------------