├── .editorconfig
├── .github
└── workflows
│ ├── pr.yml
│ ├── publish.yml
│ └── tests.yml
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── benchmark
├── README.md
├── package.json
├── src
│ ├── README.md
│ ├── benchmarks
│ │ ├── index.ts
│ │ ├── multipleKeys
│ │ │ ├── README.md
│ │ │ ├── ctrl-keys.ts
│ │ │ ├── hotkeys.ts
│ │ │ ├── shortcuts.ts
│ │ │ ├── test.ts
│ │ │ └── tinykeys.ts
│ │ └── singleKey
│ │ │ ├── README.md
│ │ │ ├── ctrl-keys.ts
│ │ │ ├── hotkeys.ts
│ │ │ ├── shortcuts.ts
│ │ │ ├── test.ts
│ │ │ └── tinykeys.ts
│ ├── config.ts
│ ├── functions
│ │ ├── benchmark
│ │ │ ├── index.ts
│ │ │ ├── press.ts
│ │ │ └── tester.ts
│ │ ├── bundle.ts
│ │ ├── index.ts
│ │ ├── measure.ts
│ │ └── render.ts
│ └── main.ts
├── tsconfig.json
└── yarn.lock
├── jest.config.js
├── package.json
├── screenshots
└── keys-autocomplete.gif
├── src
├── Handler.test.ts
├── Handler.ts
├── constants.ts
├── event.test.ts
├── event.ts
├── index.test.ts
├── index.ts
├── key.test.ts
├── key.ts
├── sequence.test.ts
├── sequence.ts
├── state.test.ts
├── state.ts
├── test-utils.ts
└── types.ts
├── tsconfig.json
├── tsup.config.ts
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 |
6 | [*.{js,ts,yml,json}]
7 | charset = utf-8
8 | indent_style = space
9 | indent_size = 2
10 |
--------------------------------------------------------------------------------
/.github/workflows/pr.yml:
--------------------------------------------------------------------------------
1 | name: PR checks
2 | on:
3 | pull_request:
4 | branches: [main]
5 | jobs:
6 | check_pr:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - uses: actions/setup-node@v1
11 | with:
12 | node-version: 20
13 | - run: yarn
14 | - run: yarn build
15 | - run: yarn test-coverage
16 | - uses: coverallsapp/github-action@master
17 | with:
18 | github-token: ${{ secrets.GITHUB_TOKEN }}
19 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 | on:
3 | push:
4 | branches: [main]
5 | jobs:
6 | publish:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | with:
11 | fetch-depth: 0
12 | - uses: actions/setup-node@v1
13 | with:
14 | node-version: 20
15 | - run: yarn
16 | - run: yarn build
17 | - name: Publish to npm
18 | uses: pascalgn/npm-publish-action@1.3.9
19 | env:
20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
21 | NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
22 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on:
3 | push:
4 | branches: [main]
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - uses: actions/setup-node@v1
11 | with:
12 | node-version: 20
13 | - run: yarn
14 | - run: yarn build
15 | - run: yarn test-coverage
16 | - uses: coverallsapp/github-action@master
17 | with:
18 | github-token: ${{ secrets.GITHUB_TOKEN }}
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | node_modules
4 | .parcel-cache
5 | dist
6 | coverage
7 | archive
8 | tasks.todo
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "printWidth": 144,
4 | "singleQuote": true,
5 | "trailingComma": "es5",
6 | "bracketSpacing": false
7 | }
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Amine Ben hammou
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ctrl-keys
2 |
3 | A tiny, super fast, typescript library to handle keybindings efficiently.
4 |
5 | [](https://bundlephobia.com/result?p=ctrl-keys)
6 | [](https://github.com/webneat/ctrl-keys/actions?query=workflow:"Tests")
7 | [](https://coveralls.io/github/webNeat/ctrl-keys?branch=master)
8 | [](https://www.npmjs.com/package/ctrl-keys)
9 | [](LICENSE)
10 |
11 | # Contents
12 | - [Features](#features)
13 | - [Installation](#installation)
14 | - [Simple usage in 3 steps](#simple-usage-in-3-steps)
15 | - [Exploring the `ctrl-keys` API](#exploring-the-ctrl-keys-api)
16 | - [Defining keybindings](#defining-keybindings)
17 | - [Adding new keybindings](#adding-new-keybindings)
18 | - [Removing keybindings](#removing-keybindings)
19 | - [Disabling and enabling keybindings](#disabling-and-enabling-keybindings)
20 | - [Handling keyboard events](#handling-keyboard-events)
21 | - [Comparaison with other keybindings libraries](#comparaison-with-other-keybindings-libraries)
22 | - [Changelog](#changelog)
23 |
24 | # Features
25 | - Zero code dependencies (Uses [`just-types`](https://github.com/webNeat/just-types) for types).
26 | - Small bundle size **< 2kb**.
27 | - Super fast performance ([see benchmark](#performance-comparaison)).
28 | - Fully typed, offers autocomplete for keybindings.
29 | - Handles multi-keys sequences like `ctrl+k ctrl+b` (Inspired by [vscode keybindings](https://code.visualstudio.com/docs/getstarted/keybindings#_keyboard-rules)).
30 | - Does not add global listeners to the `window`, instead it lets you create multiple handlers and bind them to any DOM elements.
31 | - Dynamically add, remove, enable, and disable keybindings.
32 |
33 | # Installation
34 |
35 | You can install it using `npm` or `yarn`
36 | ```bash
37 | npm i ctrl-keys
38 | // or
39 | yarn add ctrl-keys
40 | ```
41 | Or use it directly on modern browsers
42 | ```html
43 |
47 | ```
48 |
49 | _if you need to use this library on an old browser that doesn't support es modules, please open an issue and I will add a CDN that works for you_
50 |
51 | # Simple usage in 3 steps
52 |
53 | ```ts
54 | import keys from 'ctrl-keys'
55 |
56 | // 1. Create a keybindings handler
57 | const handler = keys()
58 |
59 | // 2. Add keybindings
60 | handler
61 | .add('ctrl+up', () => {
62 | // do something
63 | })
64 | .add('ctrl+shift+space', 'ctrl+shift+c', () => {
65 | // do something else ...
66 | })
67 |
68 | // 3. Handle events
69 | window.addEventListener('keydown', handler.handle)
70 | ```
71 |
72 | That's it. Now:
73 | - Whenever the `ctrl` and `up` keys are pressed at the same time; the first function will be called.
74 | - Whenever `ctrl`, `shift` and `space` keys are pressed then right after `ctrl`, `shift` and `c` are pressed; the second function will be called.
75 |
76 | Let's explore what `ctrl-keys` has to offer in more details in the next section.
77 |
78 | # Exploring the `ctrl-keys` API
79 |
80 | The default export of `ctrl-keys` is a function that takes no argument and returns a new keybindings handler:
81 |
82 | ```ts
83 | function keys(): Handler
84 | ```
85 |
86 | The handler has the following interface
87 |
88 | ```ts
89 | interface HandlerInterface {
90 | add(...keys: Keys, fn: Callback): this
91 | remove(...keys: Keys, fn: Callback): this
92 | enable(...keys: Keys): this
93 | disable(...keys: Keys): this
94 | handle(event: KeyboardEvent): boolean
95 | }
96 | ```
97 |
98 | - `add` method binds some `keys` to a function `fn` so that whenever the keys are pressed on the keyboard, that function is called.
99 | - `remove` removes the binding of `keys` to the function `fn`.
100 | - `disable` can be used to temporary disable some keys (not trigger the functions associated to them) and `enable` is used to enable them again.
101 | - `handle` handles a `KeyboardEvent` (the event emitted by `keydown` for example).
102 |
103 | We will take a deeper look to each one of these methods bellow. But first, let's see what values can we give as `keys`.
104 |
105 | ## Defining keybindings
106 |
107 | The methods `add`, `remove`, `enable` and `disable` can take **from 1 to 4** `keys`.
108 |
109 | A key is represented by a string in the following format `{modifiers}+{character}` where:
110 | - `modifiers` is any combination of the modifiers `ctrl`, `alt`, `shift` and `meta` separated by `+`.
111 | - Examples: `ctrl+alt`, `shift`, `alt+meta`, `ctrl+alt+meta`.
112 | - And `character` is one of:
113 | - `a`, `b`, ..., `z`
114 | - `0`, `1`, ..., `9`
115 | - `'`, `"`, `~`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `.`, `-`, `_`, `+`, `=`, `[`, `]`, `{`, `}`, `<`, `>`, `,`, `/`, `?`, `;`, `:`, `\`, `|`
116 | - `f1`, `f2`, ..., `f23`
117 | - `space`, `enter`, `tab`, `down`, `left`, `right`, `up`, `end`, `capslock`, `numlock`, `home`, `pagedown`, `pageup`, `backspace`, `delete`, `insert`, `escape`
118 |
119 | if you are using Typescript, it will offer autocomplete and help you detect typos when writing keys.
120 |
121 | 
122 |
123 | ## Adding new keybindings
124 |
125 | The `add` method lets you add new keybindings to the handler, you do that by specifying the keys that will be pressed and the function to call when they are pressed.
126 |
127 | ```ts
128 | const handler = keys()
129 | .add('ctrl+up', fn1) // add single key binding
130 | .add('ctrl+left', 'ctrl+up', 'ctrl+right', fn2) // add multi keys binding
131 | .add('tab', event => {
132 | // You can access the keyboard event inside the callbacks
133 | })
134 | ```
135 |
136 | You can add multiple functions to the same key
137 | ```ts
138 | handler.add('ctrl+enter', fn1)
139 | handler.add('ctrl+enter', fn2)
140 | handler.add('ctrl+enter', fn3)
141 | handler.add('ctrl+enter', fn2)
142 | ```
143 | All added functions will be called (in the same order by which they were added) when handling keyboard events that match the given keys. Adding the same function to the same keys mutiple times will only add it once (the `fn2` in the example above will only be called once when `ctrl+enter` is pressed).
144 |
145 | ## Removing keybindings
146 |
147 | The `remove` method does the opposite of `add`, it by removing keybindings from the handler.
148 |
149 | ```ts
150 | const handler = keys()
151 | .add('ctrl+a', fn1)
152 | .add('ctrl+b', fn2)
153 | .add('ctrl+a', fn3)
154 | // 'ctrl+a' calls `fn1` and `fn3`
155 | // 'ctrl+b' calls `fn2`
156 |
157 | handler.remove('ctrl+b', fn2) // now 'ctrl+b' does nothing
158 | handler.remove('ctrl+a', fn1) // now 'ctrl+a' only calls `fn3`
159 | handler.remove('ctrl+a', fn1) // does nothing because `fn1` is not bound to 'ctrl+a'
160 | ```
161 |
162 | ## Disabling and enabling keybindings
163 | The `disable` and `enable` methods let you disable/enable keybindings.
164 |
165 | ```ts
166 | const handler = keys()
167 | .add('ctrl+a', fn1)
168 | .add('ctrl+b', fn2)
169 | .add('ctrl+a', fn3)
170 | // 'ctrl+a' calls `fn1` and `fn3`
171 | // 'ctrl+b' calls `fn2`
172 |
173 | handler.disable('ctrl+a') // now 'ctrl+a' does nothing
174 | // ...
175 | handler.enable('ctrl+a') // now 'ctrl+a' calls `fn1` and `fn3`
176 | ```
177 |
178 | **Example use case**
179 | ```ts
180 | const handler = keys()
181 | .add('ctrl+a', fn1)
182 | .add('ctrl+a', fn2)
183 | .add('ctrl+a', fn3)
184 |
185 | window.addEventListener('keydown', handler.handle)
186 | ```
187 | This code will run `fn1`, `fn2` and `fn3` whenever `ctrl+a` is pressed. So if the user is typing into a textarea and presses `ctrl+a` to select all text the functions will be called which may not be the behavior we want. In that case, we can use `disable` to disable all `ctrl+a` bindings when the user starts focuses an input or textarea, and use `enable` to enable them again when the user removes focus from the input.
188 |
189 | ## Handling keyboard events
190 | `ctrl-keys` does not add listeners to `window` automatically, instead it lets you decide where and when to handle keyboard events. So after creating a handler and adding keybindings to it, you need to use its `handle` method to actually handle keyboard events
191 |
192 | ```ts
193 | window.addEventListener('keydown', event => {
194 | handler.handle(event)
195 | })
196 | ```
197 |
198 | **Note** `event.key` is used when matching events against keybindings.
199 |
200 | # Comparaison with other keybindings libraries
201 |
202 | Before creating this library, I looked around for existing libraries and found some good ones, but none of them provided everything I wanted.
203 |
204 | ## Some features comparaison
205 |
206 | | | ctrl-keys | [tinykeys](https://github.com/jamiebuilds/tinykeys) | [hotkeys](https://github.com/jaywcjlove/hotkeys) | [shortcuts](https://github.com/fabiospampinato/shortcuts) |
207 | | --- | --- | --- | --- | --- |
208 | | Bundle size | 1.23 kB | 0.72 kB | 2.5 kB | 4.4 kB |
209 | | Support for multiple keys sequences | ✅ (up to 4 keys) | ✅ | ❌ | ✅ |
210 | | Dynamically add/remove keybindings | ✅ | ❌ | ✅ | ✅ |
211 | | Gives handler instead of adding listener to `window` | ✅ | ✅ | ❌ | ❌ |
212 | | Typescript autocomplete for keybindings | ✅ | ❌ | ❌ | ❌ |
213 |
214 | ## Performance comparaison
215 |
216 |
library | duration | memory usage |
---|
ctrl-keys | 55 ms | 4711 kb |
shortcuts | 58 ms | 4963 kb |
tinykeys | 69 ms | 5056 kb |
217 |
218 | The results above are of a benchmark of handling a 3 keys sequence 1000 times. [Click here for details](https://github.com/webNeat/ctrl-keys/tree/main/benchmark)
219 |
220 | # Changelog
221 |
222 | **1.0.6 (January 31th 2025)**
223 |
224 | - Add named export to avoid default export issues with CommonJS.
225 | - Replaced `parcel` with `tsup`.
226 |
227 | **1.0.5 (January 31th 2025)**
228 |
229 | - Fix issue of 2 defautl exports.
230 |
231 | **1.0.4 (January 30th 2025)**
232 |
233 | - Update dev dependencies.
234 | - Add `module.exports` to enable `require`ing the default export.
235 |
236 | **1.0.3 (June 23th 2024)**
237 |
238 | - Update dev dependencies.
239 | - Add `exports` to package.json to fix [issue](https://github.com/webNeat/ctrl-keys/issues/8).
240 |
241 | **1.0.2 (May 1st 2024)**
242 |
243 | - Update dev dependencies.
244 | - Remove `just-types` from dependencies and bundle it in the types declaration istead.
245 |
246 | **1.0.1 (June 30th 2023)**
247 |
248 | - Update dev dependencies and benchmark.
249 | - Fix Typescript types.
250 |
251 | **1.0.0 (March 17th 2022)**
252 |
253 | - First release.
--------------------------------------------------------------------------------
/benchmark/README.md:
--------------------------------------------------------------------------------
1 | # Benchmarks
2 |
3 | The following benchmarks are a try to compare the performance (in term of time and memory usage) of `ctrl-keys` to some similar libraries. No benchmark is perfect, so it you found out that I am doing something wrong, feel free to open an issue to let me know how I can correct it, Thanks.
4 |
5 | ## How is a benchmark done?
6 |
7 | Each benchmark is done as follows:
8 |
9 | - Define a scenario to test/benchmark.
10 | - For each implementation of the scenario for a library:
11 | - Run the implementation into a web browser page (using puppeteer) and measure the time and memory it uses.
12 | - Do that measurement 100 times and return the averages.
13 |
14 | The code that measure the time and memory usage of an implementation is:
15 |
16 | ```ts
17 | // `page` is a puppeteer page
18 | await page._client.send(`HeapProfiler.collectGarbage`) // run garbage collection to free up memory
19 | const {JSHeapUsedSize: startMemory} = await page.metrics()
20 | const duration = await page.evaluate(async () => {
21 | const startTime = performance.now()
22 | // run the implementation here ...
23 | return performance.now() - startTime
24 | })
25 | const {JSHeapUsedSize: endMemory} = await page.metrics()
26 | const memory = endMemory - startMemory
27 | return {duration, memory}
28 | ```
29 |
30 | ## Single key shortcut
31 |
32 | - Setup the library to run a callback when `ctrl+b` is pressed.
33 | - Press `ctrl+a` then `ctrl+b` then `ctrl+c` 1000 times.
34 | - Wait for the library to run the callback 1000 times.
35 |
36 | ### Results
37 |
38 | library | duration | memory usage |
---|
ctrl-keys | 57 ms | 4758 kb |
shortcuts | 60 ms | 4858 kb |
tinykeys | 65 ms | 4964 kb |
39 |
40 | ## Multiple keys shortcut
41 |
42 | - Setup the library to run a callback when `ctrl+a ctrl+b ctrl+c` is pressed.
43 | - Press `ctrl+a` then `ctrl+b` then `ctrl+c` 1000 times.
44 | - Wait for the library to run the callback 1000 times.
45 |
46 | ### Results
47 |
48 | library | duration | memory usage |
---|
ctrl-keys | 59 ms | 4757 kb |
shortcuts | 61 ms | 4876 kb |
tinykeys | 70 ms | 5003 kb |
49 |
--------------------------------------------------------------------------------
/benchmark/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ctrl-keys-benchmark",
3 | "version": "1.0.0",
4 | "description": "",
5 | "scripts": {
6 | "build": "yarn ts-node src/main.ts"
7 | },
8 | "keywords": [],
9 | "author": "Amine Ben hammou",
10 | "license": "MIT",
11 | "dependencies": {
12 | "@parcel/config-default": "^2.9.3",
13 | "@parcel/core": "^2.9.3",
14 | "@parcel/fs": "^2.9.3",
15 | "@testing-library/user-event": "^14.4.3",
16 | "@types/node": "^20.3.2",
17 | "ctrl-keys": "^1.0.0",
18 | "hotkeys-js": "^3.10.3",
19 | "parcel": "^2.9.3",
20 | "puppeteer": "^13.0.0",
21 | "shortcuts": "^2.0.3",
22 | "tinykeys": "^2.1.0",
23 | "ts-node": "^10.9.1",
24 | "tslib": "^2.6.0",
25 | "typescript": "^5.1.6"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/benchmark/src/README.md:
--------------------------------------------------------------------------------
1 | # Benchmarks
2 |
3 | The following benchmarks are a try to compare the performance (in term of time and memory usage) of `ctrl-keys` to some similar libraries. No benchmark is perfect, so it you found out that I am doing something wrong, feel free to open an issue to let me know how I can correct it, Thanks.
4 |
5 | ## How is a benchmark done?
6 |
7 | Each benchmark is done as follows:
8 |
9 | - Define a scenario to test/benchmark.
10 | - For each implementation of the scenario for a library:
11 | - Run the implementation into a web browser page (using puppeteer) and measure the time and memory it uses.
12 | - Do that measurement 100 times and return the averages.
13 |
14 | The code that measure the time and memory usage of an implementation is:
15 |
16 | ```ts
17 | // `page` is a puppeteer page
18 | await page._client.send(`HeapProfiler.collectGarbage`) // run garbage collection to free up memory
19 | const {JSHeapUsedSize: startMemory} = await page.metrics()
20 | const duration = await page.evaluate(async () => {
21 | const startTime = performance.now()
22 | // run the implementation here ...
23 | return performance.now() - startTime
24 | })
25 | const {JSHeapUsedSize: endMemory} = await page.metrics()
26 | const memory = endMemory - startMemory
27 | return {duration, memory}
28 | ```
29 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/index.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | singleKey: ['tinykeys', 'ctrl-keys', 'shortcuts'],
3 | multipleKeys: ['tinykeys', 'ctrl-keys', 'shortcuts'],
4 | }
5 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/multipleKeys/README.md:
--------------------------------------------------------------------------------
1 | ## Multiple keys shortcut
2 |
3 | - Setup the library to run a callback when `ctrl+a ctrl+b ctrl+c` is pressed.
4 | - Press `ctrl+a` then `ctrl+b` then `ctrl+c` 1000 times.
5 | - Wait for the library to run the callback 1000 times.
6 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/multipleKeys/ctrl-keys.ts:
--------------------------------------------------------------------------------
1 | import keys from 'ctrl-keys'
2 | import {test} from './test'
3 |
4 | window['run_test'] = test((callback) => {
5 | const {handle} = keys().add('ctrl+a', 'ctrl+b', 'ctrl+c', callback)
6 | window.addEventListener('keydown', handle)
7 | return () => window.removeEventListener('keydown', handle)
8 | })
9 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/multipleKeys/hotkeys.ts:
--------------------------------------------------------------------------------
1 | import hotkeys from 'hotkeys-js'
2 | import {test} from './test'
3 |
4 | window['run_test'] = test((callback) => {
5 | hotkeys('ctrl+b', callback)
6 | })
7 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/multipleKeys/shortcuts.ts:
--------------------------------------------------------------------------------
1 | import {Shortcuts} from 'shortcuts'
2 | import {test} from './test'
3 |
4 | window['run_test'] = test((callback) => {
5 | const shortcuts = new Shortcuts({target: window as any})
6 | shortcuts.add({shortcut: 'Ctrl+a Ctrl+b Ctrl+c', handler: callback})
7 | return () => shortcuts.reset()
8 | })
9 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/multipleKeys/test.ts:
--------------------------------------------------------------------------------
1 | import {press, tester} from '../../functions/benchmark'
2 |
3 | export const test = tester(1000, () => {
4 | press('ctrl', 'a', 'b', 'c')
5 | })
6 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/multipleKeys/tinykeys.ts:
--------------------------------------------------------------------------------
1 | import {tinykeys} from 'tinykeys'
2 | import {test} from './test'
3 |
4 | window['run_test'] = test((callback) => {
5 | return tinykeys(window, {
6 | 'Control+a Control+b Control+c': callback,
7 | })
8 | })
9 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/singleKey/README.md:
--------------------------------------------------------------------------------
1 | ## Single key shortcut
2 |
3 | - Setup the library to run a callback when `ctrl+b` is pressed.
4 | - Press `ctrl+a` then `ctrl+b` then `ctrl+c` 1000 times.
5 | - Wait for the library to run the callback 1000 times.
6 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/singleKey/ctrl-keys.ts:
--------------------------------------------------------------------------------
1 | import keys from 'ctrl-keys'
2 | import {test} from './test'
3 |
4 | window['run_test'] = test((callback) => {
5 | const {handle} = keys().add('ctrl+b', callback)
6 | window.addEventListener('keydown', handle)
7 | return () => window.removeEventListener('keydown', handle)
8 | })
9 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/singleKey/hotkeys.ts:
--------------------------------------------------------------------------------
1 | import hotkeys from 'hotkeys-js'
2 | import {test} from './test'
3 |
4 | window['run_test'] = test((callback) => {
5 | hotkeys('ctrl+b', callback)
6 | })
7 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/singleKey/shortcuts.ts:
--------------------------------------------------------------------------------
1 | import {Shortcuts} from 'shortcuts'
2 | import {test} from './test'
3 |
4 | window['run_test'] = test((callback) => {
5 | const shortcuts = new Shortcuts({target: window as any})
6 | shortcuts.add({shortcut: 'Ctrl+b', handler: callback})
7 | return () => shortcuts.reset()
8 | })
9 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/singleKey/test.ts:
--------------------------------------------------------------------------------
1 | import {press, tester} from '../../functions/benchmark'
2 |
3 | export const test = tester(1000, () => {
4 | press('ctrl', 'a', 'b', 'c')
5 | })
6 |
--------------------------------------------------------------------------------
/benchmark/src/benchmarks/singleKey/tinykeys.ts:
--------------------------------------------------------------------------------
1 | import {tinykeys} from 'tinykeys'
2 | import {test} from './test'
3 |
4 | window['run_test'] = test((callback) => {
5 | return tinykeys(window, {
6 | 'Control+b': callback,
7 | })
8 | })
9 |
--------------------------------------------------------------------------------
/benchmark/src/config.ts:
--------------------------------------------------------------------------------
1 | export const testTimeout = 3000
2 | export const measureRepetitions = 100
3 |
--------------------------------------------------------------------------------
/benchmark/src/functions/benchmark/index.ts:
--------------------------------------------------------------------------------
1 | export * from './press'
2 | export * from './tester'
3 |
--------------------------------------------------------------------------------
/benchmark/src/functions/benchmark/press.ts:
--------------------------------------------------------------------------------
1 | const keys = {
2 | ctrl: {key: 'Control', code: 'ControlLeft', keyCode: 17},
3 | alt: {key: 'Alt', code: 'AltLeft', keyCode: 18},
4 | shift: {key: 'Shift', code: 'ShiftLeft', keyCode: 16},
5 | a: {key: 'a', code: 'KeyA', keyCode: 65},
6 | b: {key: 'b', code: 'KeyB', keyCode: 66},
7 | c: {key: 'c', code: 'KeyC', keyCode: 67},
8 | } as const
9 |
10 | type KeyName = keyof typeof keys
11 |
12 | export function press(...names: KeyName[]) {
13 | const modifiers: Record = {
14 | ctrlKey: false,
15 | altKey: false,
16 | shiftKey: false,
17 | metaKey: false,
18 | }
19 | for (const name of names) {
20 | window.dispatchEvent(new KeyboardEvent('keydown', {...keys[name], ...modifiers}))
21 | if (modifiers[`${name}Key`] === false) {
22 | modifiers[`${name}Key`] = true
23 | }
24 | }
25 | for (const name of names.reverse()) {
26 | window.dispatchEvent(new KeyboardEvent('keyup', {...keys[name], ...modifiers}))
27 | if (modifiers[`${name}Key`]) {
28 | modifiers[`${name}Key`] = false
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/benchmark/src/functions/benchmark/tester.ts:
--------------------------------------------------------------------------------
1 | import {testTimeout} from '../../config'
2 |
3 | type Callback = () => void
4 | type Handler = (fn: Callback) => Callback
5 |
6 | export const tester = (count: number, fireEvents: Callback) => (handler: Handler) => async () => {
7 | return new Promise((resolve) => {
8 | let teardown: Callback
9 | const done = () => {
10 | teardown()
11 | resolve()
12 | }
13 | const timeout = setTimeout(done, testTimeout)
14 | let step = 0
15 | const callback = () => {
16 | step++
17 | if (step === count) {
18 | clearTimeout(timeout)
19 | done()
20 | }
21 | }
22 | teardown = handler(callback)
23 | for (let i = 0; i < count; i++) fireEvents()
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/benchmark/src/functions/bundle.ts:
--------------------------------------------------------------------------------
1 | import {MemoryFS} from '@parcel/fs'
2 | import {Parcel, createWorkerFarm} from '@parcel/core'
3 |
4 | export async function bundle(path: string) {
5 | const workerFarm = createWorkerFarm()
6 | const outputFS = new MemoryFS(workerFarm)
7 | const bundler = new Parcel({
8 | entries: path,
9 | outputFS,
10 | workerFarm,
11 | mode: 'production',
12 | defaultConfig: '@parcel/config-default',
13 | defaultTargetOptions: {sourceMaps: false},
14 | })
15 | const {bundleGraph} = await bundler.run()
16 | const [bundle] = bundleGraph.getBundles()
17 | const output = await outputFS.readFile(bundle.filePath, 'utf-8')
18 | await workerFarm.end()
19 | return output
20 | }
21 |
--------------------------------------------------------------------------------
/benchmark/src/functions/index.ts:
--------------------------------------------------------------------------------
1 | export * from './bundle'
2 | export * from './measure'
3 | export * from './render'
4 |
--------------------------------------------------------------------------------
/benchmark/src/functions/measure.ts:
--------------------------------------------------------------------------------
1 | import {Browser, Page} from 'puppeteer'
2 | import {measureRepetitions} from '../config'
3 | import {bundle} from './bundle'
4 |
5 | export async function measure(browser: Browser, path: string, repetitions: number = measureRepetitions) {
6 | const content = await bundle(path)
7 | const page = await browser.newPage()
8 | await page.addScriptTag({content})
9 | await (page as any)._client.send(`HeapProfiler.enable`)
10 | let totalDuration = 0
11 | let totalMemory = 0
12 | for (let i = 0; i < repetitions; i++) {
13 | const {duration, memory} = await measureOnce(page)
14 | totalDuration += duration
15 | totalMemory += memory
16 | }
17 | await page.close()
18 | return {
19 | duration: totalDuration / repetitions,
20 | memory: totalMemory / repetitions,
21 | }
22 | }
23 |
24 | async function measureOnce(page: Page) {
25 | await (page as any)._client.send(`HeapProfiler.collectGarbage`)
26 | const {JSHeapUsedSize: startMemory} = await page.metrics()
27 | const duration = await page.evaluate(async () => {
28 | const startTime = performance.now()
29 | await window['run_test']()
30 | return performance.now() - startTime
31 | })
32 | const {JSHeapUsedSize: endMemory} = await page.metrics()
33 | const memory = endMemory - startMemory
34 | return {duration, memory}
35 | }
36 |
--------------------------------------------------------------------------------
/benchmark/src/functions/render.ts:
--------------------------------------------------------------------------------
1 | type Result = {
2 | name: string
3 | duration: number
4 | memory: number
5 | }
6 | export function render(results: Result[]) {
7 | results.sort((a, b) => a.duration - b.duration)
8 | let content = `### Results\n\n`
9 | content += `library | duration | memory usage |
`
10 | for (const {name, duration, memory} of results) {
11 | content += `${name} | ${Math.floor(duration)} ms | ${Math.floor(memory / 1000)} kb |
`
12 | }
13 | content += `
\n`
14 | return content
15 | }
16 |
--------------------------------------------------------------------------------
/benchmark/src/main.ts:
--------------------------------------------------------------------------------
1 | import pptr from 'puppeteer'
2 | import fs from 'fs/promises'
3 | import {join as joinPaths} from 'path'
4 | import {measure, render} from './functions'
5 | import benchmarks from './benchmarks'
6 |
7 | async function main() {
8 | const browser = await pptr.launch()
9 | const readme = []
10 | readme.push(await fs.readFile(joinPaths(__dirname, 'README.md'), 'utf-8'))
11 | for (const name in benchmarks) {
12 | readme.push(await fs.readFile(joinPaths(__dirname, 'benchmarks', name, 'README.md')))
13 | const tests = benchmarks[name]
14 | const results = []
15 | for (const test of tests) {
16 | console.log(name, test);
17 | const path = joinPaths(__dirname, 'benchmarks', name, test + '.ts')
18 | const {duration, memory} = await measure(browser, path)
19 | results.push({name: test, duration, memory})
20 | }
21 | readme.push(render(results))
22 | }
23 | await browser.close()
24 | await fs.writeFile('README.md', readme.join(`\n`))
25 | }
26 |
27 | main()
28 |
--------------------------------------------------------------------------------
/benchmark/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["src", "types"],
3 | "compilerOptions": {
4 | "module": "CommonJS",
5 | "target": "ESNext",
6 | "lib": ["dom", "ESNext"],
7 | "importHelpers": true,
8 | "declaration": true,
9 | "sourceMap": true,
10 | "rootDir": "src",
11 | "outDir": "build",
12 | "moduleResolution": "node",
13 | "jsx": "react",
14 | "esModuleInterop": true,
15 | "allowSyntheticDefaultImports": true,
16 | "skipLibCheck": true,
17 | "forceConsistentCasingInFileNames": true,
18 | "downlevelIteration": true
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/benchmark/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@babel/code-frame@^7.0.0":
6 | version "7.22.5"
7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658"
8 | integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==
9 | dependencies:
10 | "@babel/highlight" "^7.22.5"
11 |
12 | "@babel/helper-validator-identifier@^7.22.5":
13 | version "7.22.5"
14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
15 | integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
16 |
17 | "@babel/highlight@^7.22.5":
18 | version "7.22.5"
19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031"
20 | integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==
21 | dependencies:
22 | "@babel/helper-validator-identifier" "^7.22.5"
23 | chalk "^2.0.0"
24 | js-tokens "^4.0.0"
25 |
26 | "@cspotcode/source-map-support@^0.8.0":
27 | version "0.8.1"
28 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
29 | integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
30 | dependencies:
31 | "@jridgewell/trace-mapping" "0.3.9"
32 |
33 | "@jridgewell/resolve-uri@^3.0.3":
34 | version "3.1.1"
35 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
36 | integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
37 |
38 | "@jridgewell/sourcemap-codec@^1.4.10":
39 | version "1.4.15"
40 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
41 | integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
42 |
43 | "@jridgewell/trace-mapping@0.3.9":
44 | version "0.3.9"
45 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
46 | integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
47 | dependencies:
48 | "@jridgewell/resolve-uri" "^3.0.3"
49 | "@jridgewell/sourcemap-codec" "^1.4.10"
50 |
51 | "@lezer/common@^0.15.0", "@lezer/common@^0.15.7":
52 | version "0.15.12"
53 | resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.12.tgz#2f21aec551dd5fd7d24eb069f90f54d5bc6ee5e9"
54 | integrity sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==
55 |
56 | "@lezer/lr@^0.15.4":
57 | version "0.15.8"
58 | resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.8.tgz#1564a911e62b0a0f75ca63794a6aa8c5dc63db21"
59 | integrity sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==
60 | dependencies:
61 | "@lezer/common" "^0.15.0"
62 |
63 | "@lmdb/lmdb-darwin-arm64@2.7.11":
64 | version "2.7.11"
65 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz#b717e72f023d4215d14e4c57433c711a53c782cf"
66 | integrity sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==
67 |
68 | "@lmdb/lmdb-darwin-x64@2.7.11":
69 | version "2.7.11"
70 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz#b42898b0742b4a82b8224b742b2d174c449cd170"
71 | integrity sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==
72 |
73 | "@lmdb/lmdb-linux-arm64@2.7.11":
74 | version "2.7.11"
75 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz#a8dc8e386d27006cfccbf2a8598290b63d03a9ec"
76 | integrity sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==
77 |
78 | "@lmdb/lmdb-linux-arm@2.7.11":
79 | version "2.7.11"
80 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz#2103f48af28336efccaac008fe882dfce33e4ac5"
81 | integrity sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==
82 |
83 | "@lmdb/lmdb-linux-x64@2.7.11":
84 | version "2.7.11"
85 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz#d21ac368022a662610540f2ba8bb6ff0b96a9940"
86 | integrity sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==
87 |
88 | "@lmdb/lmdb-win32-x64@2.7.11":
89 | version "2.7.11"
90 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz#af2cb4ae6d3a92ecdeb1503b73079417525476d2"
91 | integrity sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==
92 |
93 | "@mischnic/json-sourcemap@^0.1.0":
94 | version "0.1.0"
95 | resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507"
96 | integrity sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==
97 | dependencies:
98 | "@lezer/common" "^0.15.7"
99 | "@lezer/lr" "^0.15.4"
100 | json5 "^2.2.1"
101 |
102 | "@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2":
103 | version "3.0.2"
104 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz#44d752c1a2dc113f15f781b7cc4f53a307e3fa38"
105 | integrity sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==
106 |
107 | "@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2":
108 | version "3.0.2"
109 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz#f954f34355712212a8e06c465bc06c40852c6bb3"
110 | integrity sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==
111 |
112 | "@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2":
113 | version "3.0.2"
114 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz#45c63037f045c2b15c44f80f0393fa24f9655367"
115 | integrity sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==
116 |
117 | "@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2":
118 | version "3.0.2"
119 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz#35707efeafe6d22b3f373caf9e8775e8920d1399"
120 | integrity sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==
121 |
122 | "@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2":
123 | version "3.0.2"
124 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz#091b1218b66c341f532611477ef89e83f25fae4f"
125 | integrity sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==
126 |
127 | "@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2":
128 | version "3.0.2"
129 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407"
130 | integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==
131 |
132 | "@parcel/bundler-default@2.9.3":
133 | version "2.9.3"
134 | resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.9.3.tgz#df18c4b8390a03f83ac6c89da302f9edf48c8fe2"
135 | integrity sha512-JjJK8dq39/UO/MWI/4SCbB1t/qgpQRFnFDetAAAezQ8oN++b24u1fkMDa/xqQGjbuPmGeTds5zxGgYs7id7PYg==
136 | dependencies:
137 | "@parcel/diagnostic" "2.9.3"
138 | "@parcel/graph" "2.9.3"
139 | "@parcel/hash" "2.9.3"
140 | "@parcel/plugin" "2.9.3"
141 | "@parcel/utils" "2.9.3"
142 | nullthrows "^1.1.1"
143 |
144 | "@parcel/cache@2.9.3":
145 | version "2.9.3"
146 | resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.9.3.tgz#3ed40b79858fcb7c2c73c0ed4c9807cf2388c8b4"
147 | integrity sha512-Bj/H2uAJJSXtysG7E/x4EgTrE2hXmm7td/bc97K8M9N7+vQjxf7xb0ebgqe84ePVMkj4MVQSMEJkEucXVx4b0Q==
148 | dependencies:
149 | "@parcel/fs" "2.9.3"
150 | "@parcel/logger" "2.9.3"
151 | "@parcel/utils" "2.9.3"
152 | lmdb "2.7.11"
153 |
154 | "@parcel/codeframe@2.9.3":
155 | version "2.9.3"
156 | resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.9.3.tgz#056cacaeedae9318878bdee8ffc584178b10ba42"
157 | integrity sha512-z7yTyD6h3dvduaFoHpNqur74/2yDWL++33rjQjIjCaXREBN6dKHoMGMizzo/i4vbiI1p9dDox2FIDEHCMQxqdA==
158 | dependencies:
159 | chalk "^4.1.0"
160 |
161 | "@parcel/compressor-raw@2.9.3":
162 | version "2.9.3"
163 | resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.9.3.tgz#89f5a3667d844b277ecc3811faf44fc2eeacc8d3"
164 | integrity sha512-jz3t4/ICMsHEqgiTmv5i1DJva2k5QRpZlBELVxfY+QElJTVe8edKJ0TiKcBxh2hx7sm4aUigGmp7JiqqHRRYmA==
165 | dependencies:
166 | "@parcel/plugin" "2.9.3"
167 |
168 | "@parcel/config-default@2.9.3", "@parcel/config-default@^2.9.3":
169 | version "2.9.3"
170 | resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.9.3.tgz#343172f9f91563ee6024a323eea9825ae89eedc3"
171 | integrity sha512-tqN5tF7QnVABDZAu76co5E6N8mA9n8bxiWdK4xYyINYFIEHgX172oRTqXTnhEMjlMrdmASxvnGlbaPBaVnrCTw==
172 | dependencies:
173 | "@parcel/bundler-default" "2.9.3"
174 | "@parcel/compressor-raw" "2.9.3"
175 | "@parcel/namer-default" "2.9.3"
176 | "@parcel/optimizer-css" "2.9.3"
177 | "@parcel/optimizer-htmlnano" "2.9.3"
178 | "@parcel/optimizer-image" "2.9.3"
179 | "@parcel/optimizer-svgo" "2.9.3"
180 | "@parcel/optimizer-swc" "2.9.3"
181 | "@parcel/packager-css" "2.9.3"
182 | "@parcel/packager-html" "2.9.3"
183 | "@parcel/packager-js" "2.9.3"
184 | "@parcel/packager-raw" "2.9.3"
185 | "@parcel/packager-svg" "2.9.3"
186 | "@parcel/reporter-dev-server" "2.9.3"
187 | "@parcel/resolver-default" "2.9.3"
188 | "@parcel/runtime-browser-hmr" "2.9.3"
189 | "@parcel/runtime-js" "2.9.3"
190 | "@parcel/runtime-react-refresh" "2.9.3"
191 | "@parcel/runtime-service-worker" "2.9.3"
192 | "@parcel/transformer-babel" "2.9.3"
193 | "@parcel/transformer-css" "2.9.3"
194 | "@parcel/transformer-html" "2.9.3"
195 | "@parcel/transformer-image" "2.9.3"
196 | "@parcel/transformer-js" "2.9.3"
197 | "@parcel/transformer-json" "2.9.3"
198 | "@parcel/transformer-postcss" "2.9.3"
199 | "@parcel/transformer-posthtml" "2.9.3"
200 | "@parcel/transformer-raw" "2.9.3"
201 | "@parcel/transformer-react-refresh-wrap" "2.9.3"
202 | "@parcel/transformer-svg" "2.9.3"
203 |
204 | "@parcel/core@2.9.3", "@parcel/core@^2.9.3":
205 | version "2.9.3"
206 | resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.9.3.tgz#91346afa57d7b731e7c961451462a51af940acf3"
207 | integrity sha512-4KlM1Zr/jpsqWuMXr2zmGsaOUs1zMMFh9vfCNKRZkptf+uk8I3sugHbNdo+F5B+4e2yMuOEb1zgAmvJLeuH6ww==
208 | dependencies:
209 | "@mischnic/json-sourcemap" "^0.1.0"
210 | "@parcel/cache" "2.9.3"
211 | "@parcel/diagnostic" "2.9.3"
212 | "@parcel/events" "2.9.3"
213 | "@parcel/fs" "2.9.3"
214 | "@parcel/graph" "2.9.3"
215 | "@parcel/hash" "2.9.3"
216 | "@parcel/logger" "2.9.3"
217 | "@parcel/package-manager" "2.9.3"
218 | "@parcel/plugin" "2.9.3"
219 | "@parcel/profiler" "2.9.3"
220 | "@parcel/source-map" "^2.1.1"
221 | "@parcel/types" "2.9.3"
222 | "@parcel/utils" "2.9.3"
223 | "@parcel/workers" "2.9.3"
224 | abortcontroller-polyfill "^1.1.9"
225 | base-x "^3.0.8"
226 | browserslist "^4.6.6"
227 | clone "^2.1.1"
228 | dotenv "^7.0.0"
229 | dotenv-expand "^5.1.0"
230 | json5 "^2.2.0"
231 | msgpackr "^1.5.4"
232 | nullthrows "^1.1.1"
233 | semver "^7.5.2"
234 |
235 | "@parcel/diagnostic@2.9.3":
236 | version "2.9.3"
237 | resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.9.3.tgz#23befe6c3b78440fe1e3635086e637da1529b4db"
238 | integrity sha512-6jxBdyB3D7gP4iE66ghUGntWt2v64E6EbD4AetZk+hNJpgudOOPsKTovcMi/i7I4V0qD7WXSF4tvkZUoac0jwA==
239 | dependencies:
240 | "@mischnic/json-sourcemap" "^0.1.0"
241 | nullthrows "^1.1.1"
242 |
243 | "@parcel/events@2.9.3":
244 | version "2.9.3"
245 | resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.9.3.tgz#b71253384c21f53fd3cced983cd2b287f7330e89"
246 | integrity sha512-K0Scx+Bx9f9p1vuShMzNwIgiaZUkxEnexaKYHYemJrM7pMAqxIuIqhnvwurRCsZOVLUJPDDNJ626cWTc5vIq+A==
247 |
248 | "@parcel/fs-search@2.9.3":
249 | version "2.9.3"
250 | resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.9.3.tgz#4993d68478b15db404149a271bb0084382dd2040"
251 | integrity sha512-nsNz3bsOpwS+jphcd+XjZL3F3PDq9lik0O8HPm5f6LYkqKWT+u/kgQzA8OkAHCR3q96LGiHxUywHPEBc27vI4Q==
252 |
253 | "@parcel/fs@2.9.3", "@parcel/fs@^2.9.3":
254 | version "2.9.3"
255 | resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.9.3.tgz#39abd0f71561efccaac3ba6e4b8227705b73e906"
256 | integrity sha512-/PrRKgCRw22G7rNPSpgN3Q+i2nIkZWuvIOAdMG4KWXC4XLp8C9jarNaWd5QEQ75amjhQSl3oUzABzkdCtkKrgg==
257 | dependencies:
258 | "@parcel/fs-search" "2.9.3"
259 | "@parcel/types" "2.9.3"
260 | "@parcel/utils" "2.9.3"
261 | "@parcel/watcher" "^2.0.7"
262 | "@parcel/workers" "2.9.3"
263 |
264 | "@parcel/graph@2.9.3":
265 | version "2.9.3"
266 | resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.9.3.tgz#38f6c403ff4a2741390708be510bbf328d311a63"
267 | integrity sha512-3LmRJmF8+OprAr6zJT3X2s8WAhLKkrhi6RsFlMWHifGU5ED1PFcJWFbOwJvSjcAhMQJP0fErcFIK1Ludv3Vm3g==
268 | dependencies:
269 | nullthrows "^1.1.1"
270 |
271 | "@parcel/hash@2.9.3":
272 | version "2.9.3"
273 | resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.9.3.tgz#bc7727939b1211b0a5d67fd00a9a55b8393c644a"
274 | integrity sha512-qlH5B85XLzVAeijgKPjm1gQu35LoRYX/8igsjnN8vOlbc3O8BYAUIutU58fbHbtE8MJPbxQQUw7tkTjeoujcQQ==
275 | dependencies:
276 | xxhash-wasm "^0.4.2"
277 |
278 | "@parcel/logger@2.9.3":
279 | version "2.9.3"
280 | resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.9.3.tgz#04362704d7af93d213de6587ff71a1a6d5f714ac"
281 | integrity sha512-5FNBszcV6ilGFcijEOvoNVG6IUJGsnMiaEnGQs7Fvc1dktTjEddnoQbIYhcSZL63wEmzBZOgkT5yDMajJ/41jw==
282 | dependencies:
283 | "@parcel/diagnostic" "2.9.3"
284 | "@parcel/events" "2.9.3"
285 |
286 | "@parcel/markdown-ansi@2.9.3":
287 | version "2.9.3"
288 | resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.9.3.tgz#b4de64eb252ce13e27f6e24e420b607db51097a5"
289 | integrity sha512-/Q4X8F2aN8UNjAJrQ5NfK2OmZf6shry9DqetUSEndQ0fHonk78WKt6LT0zSKEBEW/bB/bXk6mNMsCup6L8ibjQ==
290 | dependencies:
291 | chalk "^4.1.0"
292 |
293 | "@parcel/namer-default@2.9.3":
294 | version "2.9.3"
295 | resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.9.3.tgz#6dca34cbd26b29f0fd200627848c8026d58052e1"
296 | integrity sha512-1ynFEcap48/Ngzwwn318eLYpLUwijuuZoXQPCsEQ21OOIOtfhFQJaPwXTsw6kRitshKq76P2aafE0BioGSqxcA==
297 | dependencies:
298 | "@parcel/diagnostic" "2.9.3"
299 | "@parcel/plugin" "2.9.3"
300 | nullthrows "^1.1.1"
301 |
302 | "@parcel/node-resolver-core@3.0.3":
303 | version "3.0.3"
304 | resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-3.0.3.tgz#cc890e66695b6d28745415106565499af9cb3c47"
305 | integrity sha512-AjxNcZVHHJoNT/A99PKIdFtwvoze8PAiC3yz8E/dRggrDIOboUEodeQYV5Aq++aK76uz/iOP0tST2T8A5rhb1A==
306 | dependencies:
307 | "@mischnic/json-sourcemap" "^0.1.0"
308 | "@parcel/diagnostic" "2.9.3"
309 | "@parcel/fs" "2.9.3"
310 | "@parcel/utils" "2.9.3"
311 | nullthrows "^1.1.1"
312 | semver "^7.5.2"
313 |
314 | "@parcel/optimizer-css@2.9.3":
315 | version "2.9.3"
316 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.9.3.tgz#76f2f77adde9dee7498611f6be3078d0bde0396d"
317 | integrity sha512-RK1QwcSdWDNUsFvuLy0hgnYKtPQebzCb0vPPzqs6LhL+vqUu9utOyRycGaQffHCkHVQP6zGlN+KFssd7YtFGhA==
318 | dependencies:
319 | "@parcel/diagnostic" "2.9.3"
320 | "@parcel/plugin" "2.9.3"
321 | "@parcel/source-map" "^2.1.1"
322 | "@parcel/utils" "2.9.3"
323 | browserslist "^4.6.6"
324 | lightningcss "^1.16.1"
325 | nullthrows "^1.1.1"
326 |
327 | "@parcel/optimizer-htmlnano@2.9.3":
328 | version "2.9.3"
329 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.3.tgz#d5953a98892e4ba437b6e2022ad85dadacb0c84f"
330 | integrity sha512-9g/KBck3c6DokmJfvJ5zpHFBiCSolaGrcsTGx8C3YPdCTVTI9P1TDCwUxvAr4LjpcIRSa82wlLCI+nF6sSgxKA==
331 | dependencies:
332 | "@parcel/plugin" "2.9.3"
333 | htmlnano "^2.0.0"
334 | nullthrows "^1.1.1"
335 | posthtml "^0.16.5"
336 | svgo "^2.4.0"
337 |
338 | "@parcel/optimizer-image@2.9.3":
339 | version "2.9.3"
340 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.9.3.tgz#80d9be617bf2c695960ff3c5644c87c1775e1f3a"
341 | integrity sha512-530YzthE7kmecnNhPbkAK+26yQNt69pfJrgE0Ev0BZaM1Wu2+33nki7o8qvkTkikhPrurEJLGIXt1qKmbKvCbA==
342 | dependencies:
343 | "@parcel/diagnostic" "2.9.3"
344 | "@parcel/plugin" "2.9.3"
345 | "@parcel/utils" "2.9.3"
346 | "@parcel/workers" "2.9.3"
347 |
348 | "@parcel/optimizer-svgo@2.9.3":
349 | version "2.9.3"
350 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.3.tgz#e4d90f6bc1c8eeb39193759631db1bb86943bf4b"
351 | integrity sha512-ytQS0wY5JJhWU4mL0wfhYDUuHcfuw+Gy2+JcnTm1t1AZXHlOTbU6EzRWNqBShsgXjvdrQQXizAe3B6GFFlFJVQ==
352 | dependencies:
353 | "@parcel/diagnostic" "2.9.3"
354 | "@parcel/plugin" "2.9.3"
355 | "@parcel/utils" "2.9.3"
356 | svgo "^2.4.0"
357 |
358 | "@parcel/optimizer-swc@2.9.3":
359 | version "2.9.3"
360 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-swc/-/optimizer-swc-2.9.3.tgz#794a909864f76a366331f023e38082b19213c016"
361 | integrity sha512-GQINNeqtdpL1ombq/Cpwi6IBk02wKJ/JJbYbyfHtk8lxlq13soenpwOlzJ5T9D2fdG+FUhai9NxpN5Ss4lNoAg==
362 | dependencies:
363 | "@parcel/diagnostic" "2.9.3"
364 | "@parcel/plugin" "2.9.3"
365 | "@parcel/source-map" "^2.1.1"
366 | "@parcel/utils" "2.9.3"
367 | "@swc/core" "^1.3.36"
368 | nullthrows "^1.1.1"
369 |
370 | "@parcel/package-manager@2.9.3":
371 | version "2.9.3"
372 | resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.9.3.tgz#e8522671ba6c4f0a07b518957d22a038a7698b24"
373 | integrity sha512-NH6omcNTEupDmW4Lm1e4NUYBjdqkURxgZ4CNESESInHJe6tblVhNB8Rpr1ar7zDar7cly9ILr8P6N3Ei7bTEjg==
374 | dependencies:
375 | "@parcel/diagnostic" "2.9.3"
376 | "@parcel/fs" "2.9.3"
377 | "@parcel/logger" "2.9.3"
378 | "@parcel/node-resolver-core" "3.0.3"
379 | "@parcel/types" "2.9.3"
380 | "@parcel/utils" "2.9.3"
381 | "@parcel/workers" "2.9.3"
382 | semver "^7.5.2"
383 |
384 | "@parcel/packager-css@2.9.3":
385 | version "2.9.3"
386 | resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.9.3.tgz#a39a733b6e25e4f982d8b1af8bfc5d727475def0"
387 | integrity sha512-mePiWiYZOULY6e1RdAIJyRoYqXqGci0srOaVZYaP7mnrzvJgA63kaZFFsDiEWghunQpMUuUjM2x/vQVHzxmhKQ==
388 | dependencies:
389 | "@parcel/diagnostic" "2.9.3"
390 | "@parcel/plugin" "2.9.3"
391 | "@parcel/source-map" "^2.1.1"
392 | "@parcel/utils" "2.9.3"
393 | nullthrows "^1.1.1"
394 |
395 | "@parcel/packager-html@2.9.3":
396 | version "2.9.3"
397 | resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.9.3.tgz#53657c13a25e744415ece2990902a2eb6434adbe"
398 | integrity sha512-0Ex+O0EaZf9APNERRNGgGto02hFJ6f5RQEvRWBK55WAV1rXeU+kpjC0c0qZvnUaUtXfpWMsEBkevJCwDkUMeMg==
399 | dependencies:
400 | "@parcel/plugin" "2.9.3"
401 | "@parcel/types" "2.9.3"
402 | "@parcel/utils" "2.9.3"
403 | nullthrows "^1.1.1"
404 | posthtml "^0.16.5"
405 |
406 | "@parcel/packager-js@2.9.3":
407 | version "2.9.3"
408 | resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.9.3.tgz#ef8d3dde67c4da3dd83374b8d13aba9a9f3a7444"
409 | integrity sha512-V5xwkoE3zQ3R+WqAWhA1KGQ791FvJeW6KonOlMI1q76Djjgox68hhObqcLu66AmYNhR2R/wUpkP18hP2z8dSFw==
410 | dependencies:
411 | "@parcel/diagnostic" "2.9.3"
412 | "@parcel/hash" "2.9.3"
413 | "@parcel/plugin" "2.9.3"
414 | "@parcel/source-map" "^2.1.1"
415 | "@parcel/utils" "2.9.3"
416 | globals "^13.2.0"
417 | nullthrows "^1.1.1"
418 |
419 | "@parcel/packager-raw@2.9.3":
420 | version "2.9.3"
421 | resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.9.3.tgz#288335d1d1a928796dd07f13911acd2c3aefab8a"
422 | integrity sha512-oPQTNoYanQ2DdJyL61uPYK2py83rKOT8YVh2QWAx0zsSli6Kiy64U3+xOCYWgDVCrHw9+9NpQMuAdSiFg4cq8g==
423 | dependencies:
424 | "@parcel/plugin" "2.9.3"
425 |
426 | "@parcel/packager-svg@2.9.3":
427 | version "2.9.3"
428 | resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.9.3.tgz#16ae31fce0656bc8d9e9e1d5334925ed938c66d8"
429 | integrity sha512-p/Ya6UO9DAkaCUFxfFGyeHZDp9YPAlpdnh1OChuwqSFOXFjjeXuoK4KLT+ZRalVBo2Jo8xF70oKMZw4MVvaL7Q==
430 | dependencies:
431 | "@parcel/plugin" "2.9.3"
432 | "@parcel/types" "2.9.3"
433 | "@parcel/utils" "2.9.3"
434 | posthtml "^0.16.4"
435 |
436 | "@parcel/plugin@2.9.3":
437 | version "2.9.3"
438 | resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.9.3.tgz#90e9a9482fa27735494372f5643db01abcf3fdb6"
439 | integrity sha512-qN85Gqr2GMuxX1dT1mnuO9hOcvlEv1lrYrCxn7CJN2nUhbwcfG+LEvcrCzCOJ6XtIHm+ZBV9h9p7FfoPLvpw+g==
440 | dependencies:
441 | "@parcel/types" "2.9.3"
442 |
443 | "@parcel/profiler@2.9.3":
444 | version "2.9.3"
445 | resolved "https://registry.yarnpkg.com/@parcel/profiler/-/profiler-2.9.3.tgz#6575ed6dc4275c0161dce74bd719961236673ce1"
446 | integrity sha512-pyHc9lw8VZDfgZoeZWZU9J0CVEv1Zw9O5+e0DJPDPHuXJYr72ZAOhbljtU3owWKAeW+++Q2AZWkbUGEOjI/e6g==
447 | dependencies:
448 | "@parcel/diagnostic" "2.9.3"
449 | "@parcel/events" "2.9.3"
450 | chrome-trace-event "^1.0.2"
451 |
452 | "@parcel/reporter-cli@2.9.3":
453 | version "2.9.3"
454 | resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.9.3.tgz#c17e159e9b0099f7767ccfcc9cc67d28c0592763"
455 | integrity sha512-pZiEvQpuXFuQBafMHxkDmwH8CnnK9sWHwa3bSbsnt385aUahtE8dpY0LKt+K1zfB6degKoczN6aWVj9WycQuZQ==
456 | dependencies:
457 | "@parcel/plugin" "2.9.3"
458 | "@parcel/types" "2.9.3"
459 | "@parcel/utils" "2.9.3"
460 | chalk "^4.1.0"
461 | term-size "^2.2.1"
462 |
463 | "@parcel/reporter-dev-server@2.9.3":
464 | version "2.9.3"
465 | resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.3.tgz#5871d19138a1a282fa8b375d4160de7f30138f3d"
466 | integrity sha512-s6eboxdLEtRSvG52xi9IiNbcPKC0XMVmvTckieue2EqGDbDcaHQoHmmwkk0rNq0/Z/UxelGcQXoIYC/0xq3ykQ==
467 | dependencies:
468 | "@parcel/plugin" "2.9.3"
469 | "@parcel/utils" "2.9.3"
470 |
471 | "@parcel/reporter-tracer@2.9.3":
472 | version "2.9.3"
473 | resolved "https://registry.yarnpkg.com/@parcel/reporter-tracer/-/reporter-tracer-2.9.3.tgz#6ab343f5fdaeda7e6724fbaa153ab2945595e735"
474 | integrity sha512-9cXpKWk0m6d6d+4+TlAdOe8XIPaFEIKGWMWG+5SFAQE08u3olet4PSvd49F4+ZZo5ftRE7YI3j6xNbXvJT8KGw==
475 | dependencies:
476 | "@parcel/plugin" "2.9.3"
477 | "@parcel/utils" "2.9.3"
478 | chrome-trace-event "^1.0.3"
479 | nullthrows "^1.1.1"
480 |
481 | "@parcel/resolver-default@2.9.3":
482 | version "2.9.3"
483 | resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.9.3.tgz#9029e8be0efae586834243e8a8c607f739678040"
484 | integrity sha512-8ESJk1COKvDzkmOnppNXoDamNMlYVIvrKc2RuFPmp8nKVj47R6NwMgvwxEaatyPzvkmyTpq5RvG9I3HFc+r4Cw==
485 | dependencies:
486 | "@parcel/node-resolver-core" "3.0.3"
487 | "@parcel/plugin" "2.9.3"
488 |
489 | "@parcel/runtime-browser-hmr@2.9.3":
490 | version "2.9.3"
491 | resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.3.tgz#9db567aaae92c9b2b8abd26ea25ec2b549eebb54"
492 | integrity sha512-EgiDIDrVAWpz7bOzWXqVinQkaFjLwT34wsonpXAbuI7f7r00d52vNAQC9AMu+pTijA3gyKoJ+Q4NWPMZf7ACDA==
493 | dependencies:
494 | "@parcel/plugin" "2.9.3"
495 | "@parcel/utils" "2.9.3"
496 |
497 | "@parcel/runtime-js@2.9.3":
498 | version "2.9.3"
499 | resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.9.3.tgz#481c4f26705e684809bef097bf2cb75052c2982c"
500 | integrity sha512-EvIy+qXcKnB5qxHhe96zmJpSAViNVXHfQI5RSdZ2a7CPwORwhTI+zPNT9sb7xb/WwFw/WuTTgzT40b41DceU6Q==
501 | dependencies:
502 | "@parcel/diagnostic" "2.9.3"
503 | "@parcel/plugin" "2.9.3"
504 | "@parcel/utils" "2.9.3"
505 | nullthrows "^1.1.1"
506 |
507 | "@parcel/runtime-react-refresh@2.9.3":
508 | version "2.9.3"
509 | resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.3.tgz#8d82cd4fbcdc228d439bae232eb3c65d36e62872"
510 | integrity sha512-XBgryZQIyCmi6JwEfMUCmINB3l1TpTp9a2iFxmYNpzHlqj4Ve0saKaqWOVRLvC945ZovWIBzcSW2IYqWKGtbAA==
511 | dependencies:
512 | "@parcel/plugin" "2.9.3"
513 | "@parcel/utils" "2.9.3"
514 | react-error-overlay "6.0.9"
515 | react-refresh "^0.9.0"
516 |
517 | "@parcel/runtime-service-worker@2.9.3":
518 | version "2.9.3"
519 | resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.3.tgz#93dba721477c84f44458a42b28f75c875f56974d"
520 | integrity sha512-qLJLqv1mMdWL7gyh8aKBFFAuEiJkhUUgLKpdn6eSfH/R7kTtb76WnOwqUrhvEI9bZFUM/8Pa1bzJnPpqSOM+Sw==
521 | dependencies:
522 | "@parcel/plugin" "2.9.3"
523 | "@parcel/utils" "2.9.3"
524 | nullthrows "^1.1.1"
525 |
526 | "@parcel/source-map@^2.1.1":
527 | version "2.1.1"
528 | resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.1.tgz#fb193b82dba6dd62cc7a76b326f57bb35000a782"
529 | integrity sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==
530 | dependencies:
531 | detect-libc "^1.0.3"
532 |
533 | "@parcel/transformer-babel@2.9.3":
534 | version "2.9.3"
535 | resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.9.3.tgz#3527388048c606c5ef5fb909959e63be2416e87d"
536 | integrity sha512-pURtEsnsp3h6tOBDuzh9wRvVtw4PgIlqwAArIWdrG7iwqOUYv9D8ME4+ePWEu7MQWAp58hv9pTJtqWv4T+Sq8A==
537 | dependencies:
538 | "@parcel/diagnostic" "2.9.3"
539 | "@parcel/plugin" "2.9.3"
540 | "@parcel/source-map" "^2.1.1"
541 | "@parcel/utils" "2.9.3"
542 | browserslist "^4.6.6"
543 | json5 "^2.2.0"
544 | nullthrows "^1.1.1"
545 | semver "^7.5.2"
546 |
547 | "@parcel/transformer-css@2.9.3":
548 | version "2.9.3"
549 | resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.9.3.tgz#2ed58f74983d2d7fc224a6df5d17b72eb38764e4"
550 | integrity sha512-duWMdbEBBPjg3fQdXF16iWIdThetDZvCs2TpUD7xOlXH6kR0V5BJy8ONFT15u1RCqIV9hSNGaS3v3I9YRNY5zQ==
551 | dependencies:
552 | "@parcel/diagnostic" "2.9.3"
553 | "@parcel/plugin" "2.9.3"
554 | "@parcel/source-map" "^2.1.1"
555 | "@parcel/utils" "2.9.3"
556 | browserslist "^4.6.6"
557 | lightningcss "^1.16.1"
558 | nullthrows "^1.1.1"
559 |
560 | "@parcel/transformer-html@2.9.3":
561 | version "2.9.3"
562 | resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.9.3.tgz#f8b3daa4b633d81dc37772051b4e075940fa8351"
563 | integrity sha512-0NU4omcHzFXA1seqftAXA2KNZaMByoKaNdXnLgBgtCGDiYvOcL+6xGHgY6pw9LvOh5um10KI5TxSIMILoI7VtA==
564 | dependencies:
565 | "@parcel/diagnostic" "2.9.3"
566 | "@parcel/hash" "2.9.3"
567 | "@parcel/plugin" "2.9.3"
568 | nullthrows "^1.1.1"
569 | posthtml "^0.16.5"
570 | posthtml-parser "^0.10.1"
571 | posthtml-render "^3.0.0"
572 | semver "^7.5.2"
573 | srcset "4"
574 |
575 | "@parcel/transformer-image@2.9.3":
576 | version "2.9.3"
577 | resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.9.3.tgz#dd380b949e923662d3c7ced48dbe9d5b919a94e7"
578 | integrity sha512-7CEe35RaPadQzLIuxzTtIxnItvOoy46hcbXtOdDt6lmVa4omuOygZYRIya2lsGIP4JHvAaALMb5nt99a1uTwJg==
579 | dependencies:
580 | "@parcel/plugin" "2.9.3"
581 | "@parcel/utils" "2.9.3"
582 | "@parcel/workers" "2.9.3"
583 | nullthrows "^1.1.1"
584 |
585 | "@parcel/transformer-js@2.9.3":
586 | version "2.9.3"
587 | resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.9.3.tgz#4b72022da9bf5aa743a89961c4d61b681bf5e7b9"
588 | integrity sha512-Z2MVVg5FYcPOfxlUwxqb5l9yjTMEqE3KI3zq2MBRUme6AV07KxLmCDF23b6glzZlHWQUE8MXzYCTAkOPCcPz+Q==
589 | dependencies:
590 | "@parcel/diagnostic" "2.9.3"
591 | "@parcel/plugin" "2.9.3"
592 | "@parcel/source-map" "^2.1.1"
593 | "@parcel/utils" "2.9.3"
594 | "@parcel/workers" "2.9.3"
595 | "@swc/helpers" "^0.5.0"
596 | browserslist "^4.6.6"
597 | nullthrows "^1.1.1"
598 | regenerator-runtime "^0.13.7"
599 | semver "^7.5.2"
600 |
601 | "@parcel/transformer-json@2.9.3":
602 | version "2.9.3"
603 | resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.9.3.tgz#cd16bb657179f2978c7ca49c771555458cdbc307"
604 | integrity sha512-yNL27dbOLhkkrjaQjiQ7Im9VOxmkfuuSNSmS0rA3gEjVcm07SLKRzWkAaPnyx44Lb6bzyOTWwVrb9aMmxgADpA==
605 | dependencies:
606 | "@parcel/plugin" "2.9.3"
607 | json5 "^2.2.0"
608 |
609 | "@parcel/transformer-postcss@2.9.3":
610 | version "2.9.3"
611 | resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.9.3.tgz#0358facea2ea882266508e18a79390590ee812ab"
612 | integrity sha512-HoDvPqKzhpmvMmHqQhDnt8F1vH61m6plpGiYaYnYv2Om4HHi5ZIq9bO+9QLBnTKfaZ7ndYSefTKOxTYElg7wyw==
613 | dependencies:
614 | "@parcel/diagnostic" "2.9.3"
615 | "@parcel/hash" "2.9.3"
616 | "@parcel/plugin" "2.9.3"
617 | "@parcel/utils" "2.9.3"
618 | clone "^2.1.1"
619 | nullthrows "^1.1.1"
620 | postcss-value-parser "^4.2.0"
621 | semver "^7.5.2"
622 |
623 | "@parcel/transformer-posthtml@2.9.3":
624 | version "2.9.3"
625 | resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.3.tgz#dcffc9f0d667b65f9fe701753334b48b65b958d8"
626 | integrity sha512-2fQGgrzRmaqbWf3y2/T6xhqrNjzqMMKksqJzvc8TMfK6f2kg3Ddjv158eaSW2JdkV39aY7tvAOn5f1uzo74BMA==
627 | dependencies:
628 | "@parcel/plugin" "2.9.3"
629 | "@parcel/utils" "2.9.3"
630 | nullthrows "^1.1.1"
631 | posthtml "^0.16.5"
632 | posthtml-parser "^0.10.1"
633 | posthtml-render "^3.0.0"
634 | semver "^7.5.2"
635 |
636 | "@parcel/transformer-raw@2.9.3":
637 | version "2.9.3"
638 | resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.9.3.tgz#c8e23881ecb45a6dc3fcc5a271cf0d55476beabc"
639 | integrity sha512-oqdPzMC9QzWRbY9J6TZEqltknjno+dY24QWqf8ondmdF2+W+/2mRDu59hhCzQrqUHgTq4FewowRZmSfpzHxwaQ==
640 | dependencies:
641 | "@parcel/plugin" "2.9.3"
642 |
643 | "@parcel/transformer-react-refresh-wrap@2.9.3":
644 | version "2.9.3"
645 | resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.3.tgz#7775292909fa051f6dfd2668da8f34833a47d56c"
646 | integrity sha512-cb9NyU6oJlDblFIlzqIE8AkvRQVGl2IwJNKwD4PdE7Y6sq2okGEPG4hOw3k/Y9JVjM4/2pUORqvjSRhWwd9oVQ==
647 | dependencies:
648 | "@parcel/plugin" "2.9.3"
649 | "@parcel/utils" "2.9.3"
650 | react-refresh "^0.9.0"
651 |
652 | "@parcel/transformer-svg@2.9.3":
653 | version "2.9.3"
654 | resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.9.3.tgz#087a8ec63fa2377db0478a87d3e2829613b391fc"
655 | integrity sha512-ypmE+dzB09IMCdEAkOsSxq1dEIm2A3h67nAFz4qbfHbwNgXBUuy/jB3ZMwXN/cO0f7SBh/Ap8Jhq6vmGqB5tWw==
656 | dependencies:
657 | "@parcel/diagnostic" "2.9.3"
658 | "@parcel/hash" "2.9.3"
659 | "@parcel/plugin" "2.9.3"
660 | nullthrows "^1.1.1"
661 | posthtml "^0.16.5"
662 | posthtml-parser "^0.10.1"
663 | posthtml-render "^3.0.0"
664 | semver "^7.5.2"
665 |
666 | "@parcel/types@2.9.3":
667 | version "2.9.3"
668 | resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.9.3.tgz#170a26203b9088a306862b2dc914c27375d77bbc"
669 | integrity sha512-NSNY8sYtRhvF1SqhnIGgGvJocyWt1K8Tnw5cVepm0g38ywtX6mwkBvMkmeehXkII4mSUn+frD9wGsydTunezvA==
670 | dependencies:
671 | "@parcel/cache" "2.9.3"
672 | "@parcel/diagnostic" "2.9.3"
673 | "@parcel/fs" "2.9.3"
674 | "@parcel/package-manager" "2.9.3"
675 | "@parcel/source-map" "^2.1.1"
676 | "@parcel/workers" "2.9.3"
677 | utility-types "^3.10.0"
678 |
679 | "@parcel/utils@2.9.3":
680 | version "2.9.3"
681 | resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.9.3.tgz#d4df6837658f773c725a4934967ab1128a05fdd7"
682 | integrity sha512-cesanjtj/oLehW8Waq9JFPmAImhoiHX03ihc3JTWkrvJYSbD7wYKCDgPAM3JiRAqvh1LZ6P699uITrYWNoRLUg==
683 | dependencies:
684 | "@parcel/codeframe" "2.9.3"
685 | "@parcel/diagnostic" "2.9.3"
686 | "@parcel/hash" "2.9.3"
687 | "@parcel/logger" "2.9.3"
688 | "@parcel/markdown-ansi" "2.9.3"
689 | "@parcel/source-map" "^2.1.1"
690 | chalk "^4.1.0"
691 | nullthrows "^1.1.1"
692 |
693 | "@parcel/watcher@^2.0.7":
694 | version "2.1.0"
695 | resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.1.0.tgz#5f32969362db4893922c526a842d8af7a8538545"
696 | integrity sha512-8s8yYjd19pDSsBpbkOHnT6Z2+UJSuLQx61pCFM0s5wSRvKCEMDjd/cHY3/GI1szHIWbpXpsJdg3V6ISGGx9xDw==
697 | dependencies:
698 | is-glob "^4.0.3"
699 | micromatch "^4.0.5"
700 | node-addon-api "^3.2.1"
701 | node-gyp-build "^4.3.0"
702 |
703 | "@parcel/workers@2.9.3":
704 | version "2.9.3"
705 | resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.9.3.tgz#d1d84d3c767b840d0ed7123a03ab7e0f4a2c0731"
706 | integrity sha512-zRrDuZJzTevrrwElYosFztgldhqW6G9q5zOeQXfVQFkkEJCNfg36ixeiofKRU8uu2x+j+T6216mhMNB6HiuY+w==
707 | dependencies:
708 | "@parcel/diagnostic" "2.9.3"
709 | "@parcel/logger" "2.9.3"
710 | "@parcel/profiler" "2.9.3"
711 | "@parcel/types" "2.9.3"
712 | "@parcel/utils" "2.9.3"
713 | nullthrows "^1.1.1"
714 |
715 | "@swc/core-darwin-arm64@1.3.67":
716 | version "1.3.67"
717 | resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.67.tgz#8076dcd75862b92a7987a8da5a24986ab559d793"
718 | integrity sha512-zCT2mCkOBVNf5uJDcQ3A9KDoO1OEaGdfjsRTZTo7sejDd9AXLfJg+xgyCBBrK2jNS/uWcT21IvSv3LqKp4K8pA==
719 |
720 | "@swc/core-darwin-x64@1.3.67":
721 | version "1.3.67"
722 | resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.67.tgz#49da279b06232a388e9c9179db1cbff81d3dee18"
723 | integrity sha512-hXTVsfTatPEec5gFVyjGj3NccKZsYj/OXyHn6XA+l3Q76lZzGm2ISHdku//XNwXu8OmJ0HhS7LPsC4XXwxXQhg==
724 |
725 | "@swc/core-linux-arm-gnueabihf@1.3.67":
726 | version "1.3.67"
727 | resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.67.tgz#668645ac62ea7beb4319d177f43cdefb0326cd90"
728 | integrity sha512-l8AKL0RkDL5FRTeWMmjoz9zvAc37amxC+0rheaNwE+gZya7ObyNjnIYz5FwN+3y+z6JFU7LS2x/5f6iwruv6pg==
729 |
730 | "@swc/core-linux-arm64-gnu@1.3.67":
731 | version "1.3.67"
732 | resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.67.tgz#709bccc5ced37b64ab5ae479bf73fc2ab5ef0b48"
733 | integrity sha512-S8zOB1AXEpb7kmtgMaFNeLAj01VOky4B0RNZ+uJWigdrDiFT67FeZzNHUNmNSOU0QM79G+Lie/xD/beqEw0vDg==
734 |
735 | "@swc/core-linux-arm64-musl@1.3.67":
736 | version "1.3.67"
737 | resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.67.tgz#9187378e17200b1ffb3d06b78c4a33f85dd12efb"
738 | integrity sha512-Fex8J8ASrt13pmOr2xWh41tEeKWwXYGk3sV8L/aGHiYtIJEUi2f+RtMx3jp7LIdOD8pQptor7i5WBlfR9jhp8A==
739 |
740 | "@swc/core-linux-x64-gnu@1.3.67":
741 | version "1.3.67"
742 | resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.67.tgz#bcdaf46c430bc85a59ae9b38ab9bd540aa1fbd2d"
743 | integrity sha512-9bz9/bMphrv5vDg0os/d8ve0QgFpDzJgZgHUaHiGwcmfnlgdOSAaYJLIvWdcGTjZuQeV4L0m+iru357D9TXEzA==
744 |
745 | "@swc/core-linux-x64-musl@1.3.67":
746 | version "1.3.67"
747 | resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.67.tgz#fbb63517cd72eaa3250726a4209c179ada520a57"
748 | integrity sha512-ED0H6oLvQmhgo9zs8usmEA/lcZPGTu7K9og9K871b7HhHX0h/R+Xg2pb5KD7S/GyUHpfuopxjVROm+h6X1jMUA==
749 |
750 | "@swc/core-win32-arm64-msvc@1.3.67":
751 | version "1.3.67"
752 | resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.67.tgz#dadce08f9245c57e9c54c1bbcc815c4bd2077fba"
753 | integrity sha512-J1yFDLgPFeRtA8t5E159OXX+ww1gbkFg70yr4OP7EsOkOD1uMkuTf9yK/woHfsaVJlUYjJHzw7MkUIEgQBucqQ==
754 |
755 | "@swc/core-win32-ia32-msvc@1.3.67":
756 | version "1.3.67"
757 | resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.67.tgz#be026a3a389e64c24fe67a329c04eccf744ac45e"
758 | integrity sha512-bK11/KtasewqHxzkjKUBXRE9MSAidbZCxrgJUd49bItG2N/DHxkwMYu8Xkh5VDHdTYWv/2idYtf/VM9Yi+53qw==
759 |
760 | "@swc/core-win32-x64-msvc@1.3.67":
761 | version "1.3.67"
762 | resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.67.tgz#6fe2f3854d91b58f6e0b00f99366cfd84334b2ea"
763 | integrity sha512-GxzUU3+NA3cPcYxCxtfSQIS2ySD7Z8IZmKTVaWA9GOUQbKLyCE8H5js31u39+0op/1gNgxOgYFDoj2lUyvLCqw==
764 |
765 | "@swc/core@^1.3.36":
766 | version "1.3.67"
767 | resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.67.tgz#e0eb33285abb07cb0fd097d4190096977971da1e"
768 | integrity sha512-9DROjzfAEt0xt0CDkOYsWpkUPyne8fl5ggWGon049678BOM7p0R0dmaalZGAsKatG5vYP1IWSKWsKhJIubDCsQ==
769 | optionalDependencies:
770 | "@swc/core-darwin-arm64" "1.3.67"
771 | "@swc/core-darwin-x64" "1.3.67"
772 | "@swc/core-linux-arm-gnueabihf" "1.3.67"
773 | "@swc/core-linux-arm64-gnu" "1.3.67"
774 | "@swc/core-linux-arm64-musl" "1.3.67"
775 | "@swc/core-linux-x64-gnu" "1.3.67"
776 | "@swc/core-linux-x64-musl" "1.3.67"
777 | "@swc/core-win32-arm64-msvc" "1.3.67"
778 | "@swc/core-win32-ia32-msvc" "1.3.67"
779 | "@swc/core-win32-x64-msvc" "1.3.67"
780 |
781 | "@swc/helpers@^0.5.0":
782 | version "0.5.1"
783 | resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.1.tgz#e9031491aa3f26bfcc974a67f48bd456c8a5357a"
784 | integrity sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==
785 | dependencies:
786 | tslib "^2.4.0"
787 |
788 | "@testing-library/user-event@^14.4.3":
789 | version "14.4.3"
790 | resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.4.3.tgz#af975e367743fa91989cd666666aec31a8f50591"
791 | integrity sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==
792 |
793 | "@trysound/sax@0.2.0":
794 | version "0.2.0"
795 | resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
796 | integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
797 |
798 | "@tsconfig/node10@^1.0.7":
799 | version "1.0.9"
800 | resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
801 | integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
802 |
803 | "@tsconfig/node12@^1.0.7":
804 | version "1.0.11"
805 | resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
806 | integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
807 |
808 | "@tsconfig/node14@^1.0.0":
809 | version "1.0.3"
810 | resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
811 | integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
812 |
813 | "@tsconfig/node16@^1.0.2":
814 | version "1.0.4"
815 | resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9"
816 | integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==
817 |
818 | "@types/node@*", "@types/node@^20.3.2":
819 | version "20.3.2"
820 | resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.2.tgz#fa6a90f2600e052a03c18b8cb3fd83dd4e599898"
821 | integrity sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==
822 |
823 | "@types/yauzl@^2.9.1":
824 | version "2.10.0"
825 | resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599"
826 | integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==
827 | dependencies:
828 | "@types/node" "*"
829 |
830 | abortcontroller-polyfill@^1.1.9:
831 | version "1.7.5"
832 | resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed"
833 | integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==
834 |
835 | acorn-walk@^8.1.1:
836 | version "8.2.0"
837 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
838 | integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
839 |
840 | acorn@^8.4.1:
841 | version "8.9.0"
842 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.9.0.tgz#78a16e3b2bcc198c10822786fa6679e245db5b59"
843 | integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==
844 |
845 | agent-base@6:
846 | version "6.0.2"
847 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
848 | integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
849 | dependencies:
850 | debug "4"
851 |
852 | ansi-styles@^3.2.1:
853 | version "3.2.1"
854 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
855 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
856 | dependencies:
857 | color-convert "^1.9.0"
858 |
859 | ansi-styles@^4.1.0:
860 | version "4.3.0"
861 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
862 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
863 | dependencies:
864 | color-convert "^2.0.1"
865 |
866 | arg@^4.1.0:
867 | version "4.1.3"
868 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
869 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
870 |
871 | argparse@^2.0.1:
872 | version "2.0.1"
873 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
874 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
875 |
876 | balanced-match@^1.0.0:
877 | version "1.0.2"
878 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
879 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
880 |
881 | base-x@^3.0.8:
882 | version "3.0.9"
883 | resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
884 | integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==
885 | dependencies:
886 | safe-buffer "^5.0.1"
887 |
888 | base64-js@^1.3.1:
889 | version "1.5.1"
890 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
891 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
892 |
893 | bl@^4.0.3:
894 | version "4.1.0"
895 | resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
896 | integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
897 | dependencies:
898 | buffer "^5.5.0"
899 | inherits "^2.0.4"
900 | readable-stream "^3.4.0"
901 |
902 | boolbase@^1.0.0:
903 | version "1.0.0"
904 | resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
905 | integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
906 |
907 | brace-expansion@^1.1.7:
908 | version "1.1.11"
909 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
910 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
911 | dependencies:
912 | balanced-match "^1.0.0"
913 | concat-map "0.0.1"
914 |
915 | braces@^3.0.2:
916 | version "3.0.2"
917 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
918 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
919 | dependencies:
920 | fill-range "^7.0.1"
921 |
922 | browserslist@^4.6.6:
923 | version "4.21.9"
924 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635"
925 | integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==
926 | dependencies:
927 | caniuse-lite "^1.0.30001503"
928 | electron-to-chromium "^1.4.431"
929 | node-releases "^2.0.12"
930 | update-browserslist-db "^1.0.11"
931 |
932 | buffer-crc32@~0.2.3:
933 | version "0.2.13"
934 | resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
935 | integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
936 |
937 | buffer@^5.2.1, buffer@^5.5.0:
938 | version "5.7.1"
939 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
940 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
941 | dependencies:
942 | base64-js "^1.3.1"
943 | ieee754 "^1.1.13"
944 |
945 | callsites@^3.0.0:
946 | version "3.1.0"
947 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
948 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
949 |
950 | caniuse-lite@^1.0.30001503:
951 | version "1.0.30001509"
952 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz#2b7ad5265392d6d2de25cd8776d1ab3899570d14"
953 | integrity sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==
954 |
955 | chalk@^2.0.0:
956 | version "2.4.2"
957 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
958 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
959 | dependencies:
960 | ansi-styles "^3.2.1"
961 | escape-string-regexp "^1.0.5"
962 | supports-color "^5.3.0"
963 |
964 | chalk@^4.1.0:
965 | version "4.1.2"
966 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
967 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
968 | dependencies:
969 | ansi-styles "^4.1.0"
970 | supports-color "^7.1.0"
971 |
972 | chownr@^1.1.1:
973 | version "1.1.4"
974 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
975 | integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
976 |
977 | chrome-trace-event@^1.0.2, chrome-trace-event@^1.0.3:
978 | version "1.0.3"
979 | resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
980 | integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
981 |
982 | clone@^2.1.1:
983 | version "2.1.2"
984 | resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
985 | integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
986 |
987 | color-convert@^1.9.0:
988 | version "1.9.3"
989 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
990 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
991 | dependencies:
992 | color-name "1.1.3"
993 |
994 | color-convert@^2.0.1:
995 | version "2.0.1"
996 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
997 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
998 | dependencies:
999 | color-name "~1.1.4"
1000 |
1001 | color-name@1.1.3:
1002 | version "1.1.3"
1003 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
1004 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
1005 |
1006 | color-name@~1.1.4:
1007 | version "1.1.4"
1008 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
1009 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
1010 |
1011 | commander@^7.0.0, commander@^7.2.0:
1012 | version "7.2.0"
1013 | resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
1014 | integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
1015 |
1016 | concat-map@0.0.1:
1017 | version "0.0.1"
1018 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
1019 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
1020 |
1021 | cosmiconfig@^8.0.0:
1022 | version "8.2.0"
1023 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd"
1024 | integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==
1025 | dependencies:
1026 | import-fresh "^3.2.1"
1027 | js-yaml "^4.1.0"
1028 | parse-json "^5.0.0"
1029 | path-type "^4.0.0"
1030 |
1031 | create-require@^1.1.0:
1032 | version "1.1.1"
1033 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
1034 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
1035 |
1036 | cross-fetch@3.1.5:
1037 | version "3.1.5"
1038 | resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
1039 | integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
1040 | dependencies:
1041 | node-fetch "2.6.7"
1042 |
1043 | css-select@^4.1.3:
1044 | version "4.3.0"
1045 | resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
1046 | integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
1047 | dependencies:
1048 | boolbase "^1.0.0"
1049 | css-what "^6.0.1"
1050 | domhandler "^4.3.1"
1051 | domutils "^2.8.0"
1052 | nth-check "^2.0.1"
1053 |
1054 | css-tree@^1.1.2, css-tree@^1.1.3:
1055 | version "1.1.3"
1056 | resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
1057 | integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
1058 | dependencies:
1059 | mdn-data "2.0.14"
1060 | source-map "^0.6.1"
1061 |
1062 | css-what@^6.0.1:
1063 | version "6.1.0"
1064 | resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
1065 | integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
1066 |
1067 | csso@^4.2.0:
1068 | version "4.2.0"
1069 | resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
1070 | integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
1071 | dependencies:
1072 | css-tree "^1.1.2"
1073 |
1074 | ctrl-keys@^1.0.0:
1075 | version "1.0.0"
1076 | resolved "https://registry.yarnpkg.com/ctrl-keys/-/ctrl-keys-1.0.0.tgz#df2b7c094953a30d56388d407292452c1e4bcab0"
1077 | integrity sha512-O0x/SkzRJtcqDJwA8MyHbaDnDuJ6Z044Y/C5pd3MzjfMgc7/7MR77HTTLVmpUc0Tc32UWMQ9zq9ZHjR3ehYd/Q==
1078 | dependencies:
1079 | just-types "^1.4.0"
1080 |
1081 | debug@4, debug@4.3.4, debug@^4.1.1:
1082 | version "4.3.4"
1083 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
1084 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
1085 | dependencies:
1086 | ms "2.1.2"
1087 |
1088 | detect-libc@^1.0.3:
1089 | version "1.0.3"
1090 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
1091 | integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
1092 |
1093 | devtools-protocol@0.0.981744:
1094 | version "0.0.981744"
1095 | resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.981744.tgz#9960da0370284577d46c28979a0b32651022bacf"
1096 | integrity sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==
1097 |
1098 | diff@^4.0.1:
1099 | version "4.0.2"
1100 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
1101 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
1102 |
1103 | dom-serializer@^1.0.1:
1104 | version "1.4.1"
1105 | resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
1106 | integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
1107 | dependencies:
1108 | domelementtype "^2.0.1"
1109 | domhandler "^4.2.0"
1110 | entities "^2.0.0"
1111 |
1112 | domelementtype@^2.0.1, domelementtype@^2.2.0:
1113 | version "2.3.0"
1114 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
1115 | integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
1116 |
1117 | domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1:
1118 | version "4.3.1"
1119 | resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
1120 | integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
1121 | dependencies:
1122 | domelementtype "^2.2.0"
1123 |
1124 | domutils@^2.8.0:
1125 | version "2.8.0"
1126 | resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
1127 | integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
1128 | dependencies:
1129 | dom-serializer "^1.0.1"
1130 | domelementtype "^2.2.0"
1131 | domhandler "^4.2.0"
1132 |
1133 | dotenv-expand@^5.1.0:
1134 | version "5.1.0"
1135 | resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
1136 | integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
1137 |
1138 | dotenv@^7.0.0:
1139 | version "7.0.0"
1140 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c"
1141 | integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==
1142 |
1143 | electron-to-chromium@^1.4.431:
1144 | version "1.4.445"
1145 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.445.tgz#058d2c5f3a2981ab1a37440f5a5e42d15672aa6d"
1146 | integrity sha512-++DB+9VK8SBJwC+X1zlMfJ1tMA3F0ipi39GdEp+x3cV2TyBihqAgad8cNMWtLDEkbH39nlDQP7PfGrDr3Dr7HA==
1147 |
1148 | end-of-stream@^1.1.0, end-of-stream@^1.4.1:
1149 | version "1.4.4"
1150 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
1151 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
1152 | dependencies:
1153 | once "^1.4.0"
1154 |
1155 | entities@^2.0.0:
1156 | version "2.2.0"
1157 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
1158 | integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
1159 |
1160 | entities@^3.0.1:
1161 | version "3.0.1"
1162 | resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
1163 | integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
1164 |
1165 | error-ex@^1.3.1:
1166 | version "1.3.2"
1167 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
1168 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
1169 | dependencies:
1170 | is-arrayish "^0.2.1"
1171 |
1172 | escalade@^3.1.1:
1173 | version "3.1.1"
1174 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
1175 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
1176 |
1177 | escape-string-regexp@^1.0.5:
1178 | version "1.0.5"
1179 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
1180 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
1181 |
1182 | extract-zip@2.0.1:
1183 | version "2.0.1"
1184 | resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
1185 | integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
1186 | dependencies:
1187 | debug "^4.1.1"
1188 | get-stream "^5.1.0"
1189 | yauzl "^2.10.0"
1190 | optionalDependencies:
1191 | "@types/yauzl" "^2.9.1"
1192 |
1193 | fd-slicer@~1.1.0:
1194 | version "1.1.0"
1195 | resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
1196 | integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==
1197 | dependencies:
1198 | pend "~1.2.0"
1199 |
1200 | fill-range@^7.0.1:
1201 | version "7.0.1"
1202 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
1203 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
1204 | dependencies:
1205 | to-regex-range "^5.0.1"
1206 |
1207 | find-up@^4.0.0:
1208 | version "4.1.0"
1209 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
1210 | integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
1211 | dependencies:
1212 | locate-path "^5.0.0"
1213 | path-exists "^4.0.0"
1214 |
1215 | fs-constants@^1.0.0:
1216 | version "1.0.0"
1217 | resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
1218 | integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
1219 |
1220 | fs.realpath@^1.0.0:
1221 | version "1.0.0"
1222 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
1223 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
1224 |
1225 | get-port@^4.2.0:
1226 | version "4.2.0"
1227 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119"
1228 | integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==
1229 |
1230 | get-stream@^5.1.0:
1231 | version "5.2.0"
1232 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
1233 | integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
1234 | dependencies:
1235 | pump "^3.0.0"
1236 |
1237 | glob@^7.1.3:
1238 | version "7.2.3"
1239 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
1240 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
1241 | dependencies:
1242 | fs.realpath "^1.0.0"
1243 | inflight "^1.0.4"
1244 | inherits "2"
1245 | minimatch "^3.1.1"
1246 | once "^1.3.0"
1247 | path-is-absolute "^1.0.0"
1248 |
1249 | globals@^13.2.0:
1250 | version "13.20.0"
1251 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
1252 | integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
1253 | dependencies:
1254 | type-fest "^0.20.2"
1255 |
1256 | has-flag@^3.0.0:
1257 | version "3.0.0"
1258 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
1259 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
1260 |
1261 | has-flag@^4.0.0:
1262 | version "4.0.0"
1263 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
1264 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
1265 |
1266 | hotkeys-js@^3.10.3:
1267 | version "3.10.3"
1268 | resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.10.3.tgz#c529aab772f7afea0ddb28b2577c0cd56cd47336"
1269 | integrity sha512-QEUlDS8gh8nJ4EpkZbSYR0qG4X6mZfQTGPsW89hTw5To5BcvDz0MOx9tZf8uCu1FswAbowEiyMN00iKMN2nH7Q==
1270 |
1271 | htmlnano@^2.0.0:
1272 | version "2.0.4"
1273 | resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.0.4.tgz#315108063ed0bb6a16ccb53ad1b601f02d3fe721"
1274 | integrity sha512-WGCkyGFwjKW1GeCBsPYacMvaMnZtFJ0zIRnC2NCddkA+IOEhTqskXrS7lep+3yYZw/nQ3dW1UAX4yA/GJyR8BA==
1275 | dependencies:
1276 | cosmiconfig "^8.0.0"
1277 | posthtml "^0.16.5"
1278 | timsort "^0.3.0"
1279 |
1280 | htmlparser2@^7.1.1:
1281 | version "7.2.0"
1282 | resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5"
1283 | integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==
1284 | dependencies:
1285 | domelementtype "^2.0.1"
1286 | domhandler "^4.2.2"
1287 | domutils "^2.8.0"
1288 | entities "^3.0.1"
1289 |
1290 | https-proxy-agent@5.0.1:
1291 | version "5.0.1"
1292 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
1293 | integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
1294 | dependencies:
1295 | agent-base "6"
1296 | debug "4"
1297 |
1298 | ieee754@^1.1.13:
1299 | version "1.2.1"
1300 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
1301 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
1302 |
1303 | import-fresh@^3.2.1:
1304 | version "3.3.0"
1305 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
1306 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
1307 | dependencies:
1308 | parent-module "^1.0.0"
1309 | resolve-from "^4.0.0"
1310 |
1311 | inflight@^1.0.4:
1312 | version "1.0.6"
1313 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
1314 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
1315 | dependencies:
1316 | once "^1.3.0"
1317 | wrappy "1"
1318 |
1319 | inherits@2, inherits@^2.0.3, inherits@^2.0.4:
1320 | version "2.0.4"
1321 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
1322 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
1323 |
1324 | is-arrayish@^0.2.1:
1325 | version "0.2.1"
1326 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
1327 | integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
1328 |
1329 | is-extglob@^2.1.1:
1330 | version "2.1.1"
1331 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
1332 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
1333 |
1334 | is-glob@^4.0.3:
1335 | version "4.0.3"
1336 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
1337 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
1338 | dependencies:
1339 | is-extglob "^2.1.1"
1340 |
1341 | is-json@^2.0.1:
1342 | version "2.0.1"
1343 | resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff"
1344 | integrity sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==
1345 |
1346 | is-number@^7.0.0:
1347 | version "7.0.0"
1348 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
1349 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
1350 |
1351 | js-tokens@^4.0.0:
1352 | version "4.0.0"
1353 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
1354 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
1355 |
1356 | js-yaml@^4.1.0:
1357 | version "4.1.0"
1358 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
1359 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
1360 | dependencies:
1361 | argparse "^2.0.1"
1362 |
1363 | json-parse-even-better-errors@^2.3.0:
1364 | version "2.3.1"
1365 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
1366 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
1367 |
1368 | json5@^2.2.0, json5@^2.2.1:
1369 | version "2.2.3"
1370 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
1371 | integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
1372 |
1373 | just-types@^1.4.0:
1374 | version "1.6.0"
1375 | resolved "https://registry.yarnpkg.com/just-types/-/just-types-1.6.0.tgz#961e4971e5640f20790587897ab30fc85366e33c"
1376 | integrity sha512-CcPlKiJa5YgRbvoL1w71PkB6oOkn2hBzlY1jZXfw/1Crip2Q36ruLkv5nCCjQKWkW7aADVL1U7jXj0ptLMFkdQ==
1377 |
1378 | lightningcss-darwin-arm64@1.21.1:
1379 | version "1.21.1"
1380 | resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.1.tgz#595b45510a3637c4b85be513dd029bade6abf0e7"
1381 | integrity sha512-dljpsZ15RN4AxI958n9qO7sAv29FRuUMCB10CSDBGmDOW+oDDbNLs1k5/7MlYg5FXnZqznUSTtHBFHFyo1Rs2Q==
1382 |
1383 | lightningcss-darwin-x64@1.21.1:
1384 | version "1.21.1"
1385 | resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.1.tgz#d8ca5997794b7d8bec8e7390da848c2cb865ac33"
1386 | integrity sha512-e/dAKKOcLe2F/A5a89gh03ABxZHn4yjGapGimCFxnCpg68iIdtoPrJTFAyxPV3Jty4djLYRlitoIWNidOK35zA==
1387 |
1388 | lightningcss-linux-arm-gnueabihf@1.21.1:
1389 | version "1.21.1"
1390 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.1.tgz#7581480a3ad4a5f5b80e7a1b1db787ec086267e0"
1391 | integrity sha512-Ak12ti7D4Q9Tk3tX9fktCJVe+spP12/dOcebw67DBeZ3EQ4meIGTkFpl2ryZK8Z7kbIJNUsscVsz3zXW21/25A==
1392 |
1393 | lightningcss-linux-arm64-gnu@1.21.1:
1394 | version "1.21.1"
1395 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.1.tgz#1744af42b0a610661aaa17cdd5eb2e3ec65eda3d"
1396 | integrity sha512-ggCX0iyG/h2C1MfDfmfhB0zpEUTTP+kG9XBbwHRFKrQsmb3b7WC5QiyVuGYkzoGiHy1JNuyi27qR9cNVLCR8FQ==
1397 |
1398 | lightningcss-linux-arm64-musl@1.21.1:
1399 | version "1.21.1"
1400 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.1.tgz#b59848d392542210e1caa7a1abff16c7d0adb1cc"
1401 | integrity sha512-vGaVLju7Zhus/sl5Oz/1YbV7L/Mr/bfjHbThj/DJcFggZPj1wfSeWc6gAAISqK3bIAUMVlcUEm2UnIDGj0tsOQ==
1402 |
1403 | lightningcss-linux-x64-gnu@1.21.1:
1404 | version "1.21.1"
1405 | resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.1.tgz#111a5ac18b99c5ea1478cc0684cfcc651c35ccb6"
1406 | integrity sha512-W6b+ndCCO/SeIT4s7kJhkJGXZVz96uwb7eY61SwCAibs5HirzRMrIyuMY3JKcRESg9/jysHo4YWrr1icbzWiXw==
1407 |
1408 | lightningcss-linux-x64-musl@1.21.1:
1409 | version "1.21.1"
1410 | resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.1.tgz#6ed62f9e0f2dc9361edaa722836bdf495e28e2de"
1411 | integrity sha512-eA2ygIg/IbjglRq/QRCDTgnR8mtmXJ65t/1C1QUUvvexWfr0iiTKJj3iozgUKZmupfomrPIhF3Qya0el9PqjUA==
1412 |
1413 | lightningcss-win32-x64-msvc@1.21.1:
1414 | version "1.21.1"
1415 | resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.1.tgz#b79b91887b522007f2ee30d37727e1540172ddb3"
1416 | integrity sha512-2PKZvhrMxr7TjceUkkAtNQtDOEozcbp8GdcOKCrhNmrQ1OT8Mm5p4sMp7bzT0QytT7W5EuhIteWQFW/qI64Wtw==
1417 |
1418 | lightningcss@^1.16.1:
1419 | version "1.21.1"
1420 | resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.21.1.tgz#4d1f87a08db839009af1a24fd7cc13bd24a5acb5"
1421 | integrity sha512-TKkVZzKnJVtGLI+8QMXLH2JdNcxjodA06So+uXA5qelvuReKvPyCJBX/6ZznADA76zNijmDc3OhjxvTBmNtCoA==
1422 | dependencies:
1423 | detect-libc "^1.0.3"
1424 | optionalDependencies:
1425 | lightningcss-darwin-arm64 "1.21.1"
1426 | lightningcss-darwin-x64 "1.21.1"
1427 | lightningcss-linux-arm-gnueabihf "1.21.1"
1428 | lightningcss-linux-arm64-gnu "1.21.1"
1429 | lightningcss-linux-arm64-musl "1.21.1"
1430 | lightningcss-linux-x64-gnu "1.21.1"
1431 | lightningcss-linux-x64-musl "1.21.1"
1432 | lightningcss-win32-x64-msvc "1.21.1"
1433 |
1434 | lines-and-columns@^1.1.6:
1435 | version "1.2.4"
1436 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
1437 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
1438 |
1439 | lmdb@2.7.11:
1440 | version "2.7.11"
1441 | resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.7.11.tgz#a24b6d36b5c7ed9889cc2d9e103fdd3f5e144d7e"
1442 | integrity sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==
1443 | dependencies:
1444 | msgpackr "1.8.5"
1445 | node-addon-api "^4.3.0"
1446 | node-gyp-build-optional-packages "5.0.6"
1447 | ordered-binary "^1.4.0"
1448 | weak-lru-cache "^1.2.2"
1449 | optionalDependencies:
1450 | "@lmdb/lmdb-darwin-arm64" "2.7.11"
1451 | "@lmdb/lmdb-darwin-x64" "2.7.11"
1452 | "@lmdb/lmdb-linux-arm" "2.7.11"
1453 | "@lmdb/lmdb-linux-arm64" "2.7.11"
1454 | "@lmdb/lmdb-linux-x64" "2.7.11"
1455 | "@lmdb/lmdb-win32-x64" "2.7.11"
1456 |
1457 | locate-path@^5.0.0:
1458 | version "5.0.0"
1459 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
1460 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
1461 | dependencies:
1462 | p-locate "^4.1.0"
1463 |
1464 | lru-cache@^6.0.0:
1465 | version "6.0.0"
1466 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
1467 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
1468 | dependencies:
1469 | yallist "^4.0.0"
1470 |
1471 | make-error@^1.1.1:
1472 | version "1.3.6"
1473 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
1474 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
1475 |
1476 | mdn-data@2.0.14:
1477 | version "2.0.14"
1478 | resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
1479 | integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
1480 |
1481 | micromatch@^4.0.5:
1482 | version "4.0.5"
1483 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
1484 | integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
1485 | dependencies:
1486 | braces "^3.0.2"
1487 | picomatch "^2.3.1"
1488 |
1489 | minimatch@^3.1.1:
1490 | version "3.1.2"
1491 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
1492 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
1493 | dependencies:
1494 | brace-expansion "^1.1.7"
1495 |
1496 | mkdirp-classic@^0.5.2:
1497 | version "0.5.3"
1498 | resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
1499 | integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
1500 |
1501 | ms@2.1.2:
1502 | version "2.1.2"
1503 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
1504 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
1505 |
1506 | msgpackr-extract@^3.0.1, msgpackr-extract@^3.0.2:
1507 | version "3.0.2"
1508 | resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz#e05ec1bb4453ddf020551bcd5daaf0092a2c279d"
1509 | integrity sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==
1510 | dependencies:
1511 | node-gyp-build-optional-packages "5.0.7"
1512 | optionalDependencies:
1513 | "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.2"
1514 | "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.2"
1515 | "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.2"
1516 | "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.2"
1517 | "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2"
1518 | "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2"
1519 |
1520 | msgpackr@1.8.5:
1521 | version "1.8.5"
1522 | resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.5.tgz#8cadfb935357680648f33699d0e833c9179dbfeb"
1523 | integrity sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==
1524 | optionalDependencies:
1525 | msgpackr-extract "^3.0.1"
1526 |
1527 | msgpackr@^1.5.4:
1528 | version "1.9.5"
1529 | resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.9.5.tgz#ac548c5f4546db895e84e46d39d813be961dc527"
1530 | integrity sha512-/IJ3cFSN6Ci3eG2wLhbFEL6GT63yEaoN/R5My2QkV6zro+OJaVRLPlwvxY7EtHYSmDlQpk8stvOQTL2qJFkDRg==
1531 | optionalDependencies:
1532 | msgpackr-extract "^3.0.2"
1533 |
1534 | node-addon-api@^3.2.1:
1535 | version "3.2.1"
1536 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
1537 | integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==
1538 |
1539 | node-addon-api@^4.3.0:
1540 | version "4.3.0"
1541 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
1542 | integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
1543 |
1544 | node-fetch@2.6.7:
1545 | version "2.6.7"
1546 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
1547 | integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
1548 | dependencies:
1549 | whatwg-url "^5.0.0"
1550 |
1551 | node-gyp-build-optional-packages@5.0.6:
1552 | version "5.0.6"
1553 | resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz#2949f5cc7dace3ac470fa2ff1a37456907120a1d"
1554 | integrity sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==
1555 |
1556 | node-gyp-build-optional-packages@5.0.7:
1557 | version "5.0.7"
1558 | resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3"
1559 | integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==
1560 |
1561 | node-gyp-build@^4.3.0:
1562 | version "4.6.0"
1563 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055"
1564 | integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==
1565 |
1566 | node-releases@^2.0.12:
1567 | version "2.0.12"
1568 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039"
1569 | integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==
1570 |
1571 | nth-check@^2.0.1:
1572 | version "2.1.1"
1573 | resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
1574 | integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
1575 | dependencies:
1576 | boolbase "^1.0.0"
1577 |
1578 | nullthrows@^1.1.1:
1579 | version "1.1.1"
1580 | resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1"
1581 | integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==
1582 |
1583 | once@^1.3.0, once@^1.3.1, once@^1.4.0:
1584 | version "1.4.0"
1585 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
1586 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
1587 | dependencies:
1588 | wrappy "1"
1589 |
1590 | ordered-binary@^1.4.0:
1591 | version "1.4.0"
1592 | resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.4.0.tgz#6bb53d44925f3b8afc33d1eed0fa15693b211389"
1593 | integrity sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ==
1594 |
1595 | p-limit@^2.2.0:
1596 | version "2.3.0"
1597 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
1598 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
1599 | dependencies:
1600 | p-try "^2.0.0"
1601 |
1602 | p-locate@^4.1.0:
1603 | version "4.1.0"
1604 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
1605 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
1606 | dependencies:
1607 | p-limit "^2.2.0"
1608 |
1609 | p-try@^2.0.0:
1610 | version "2.2.0"
1611 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
1612 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
1613 |
1614 | parcel@^2.9.3:
1615 | version "2.9.3"
1616 | resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.9.3.tgz#315660ccbaa5a830cf71280ab0cfbd3079247cc5"
1617 | integrity sha512-2GTVocFkwblV/TIg9AmT7TI2fO4xdWkyN8aFUEVtiVNWt96GTR3FgQyHFValfCbcj1k9Xf962Ws2hYXYUr9k1Q==
1618 | dependencies:
1619 | "@parcel/config-default" "2.9.3"
1620 | "@parcel/core" "2.9.3"
1621 | "@parcel/diagnostic" "2.9.3"
1622 | "@parcel/events" "2.9.3"
1623 | "@parcel/fs" "2.9.3"
1624 | "@parcel/logger" "2.9.3"
1625 | "@parcel/package-manager" "2.9.3"
1626 | "@parcel/reporter-cli" "2.9.3"
1627 | "@parcel/reporter-dev-server" "2.9.3"
1628 | "@parcel/reporter-tracer" "2.9.3"
1629 | "@parcel/utils" "2.9.3"
1630 | chalk "^4.1.0"
1631 | commander "^7.0.0"
1632 | get-port "^4.2.0"
1633 |
1634 | parent-module@^1.0.0:
1635 | version "1.0.1"
1636 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
1637 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
1638 | dependencies:
1639 | callsites "^3.0.0"
1640 |
1641 | parse-json@^5.0.0:
1642 | version "5.2.0"
1643 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
1644 | integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
1645 | dependencies:
1646 | "@babel/code-frame" "^7.0.0"
1647 | error-ex "^1.3.1"
1648 | json-parse-even-better-errors "^2.3.0"
1649 | lines-and-columns "^1.1.6"
1650 |
1651 | path-exists@^4.0.0:
1652 | version "4.0.0"
1653 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
1654 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
1655 |
1656 | path-is-absolute@^1.0.0:
1657 | version "1.0.1"
1658 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
1659 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
1660 |
1661 | path-type@^4.0.0:
1662 | version "4.0.0"
1663 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
1664 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
1665 |
1666 | pend@~1.2.0:
1667 | version "1.2.0"
1668 | resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
1669 | integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==
1670 |
1671 | picocolors@^1.0.0:
1672 | version "1.0.0"
1673 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
1674 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
1675 |
1676 | picomatch@^2.3.1:
1677 | version "2.3.1"
1678 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
1679 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
1680 |
1681 | pkg-dir@4.2.0:
1682 | version "4.2.0"
1683 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
1684 | integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
1685 | dependencies:
1686 | find-up "^4.0.0"
1687 |
1688 | postcss-value-parser@^4.2.0:
1689 | version "4.2.0"
1690 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
1691 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
1692 |
1693 | posthtml-parser@^0.10.1:
1694 | version "0.10.2"
1695 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.2.tgz#df364d7b179f2a6bf0466b56be7b98fd4e97c573"
1696 | integrity sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==
1697 | dependencies:
1698 | htmlparser2 "^7.1.1"
1699 |
1700 | posthtml-parser@^0.11.0:
1701 | version "0.11.0"
1702 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.11.0.tgz#25d1c7bf811ea83559bc4c21c189a29747a24b7a"
1703 | integrity sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==
1704 | dependencies:
1705 | htmlparser2 "^7.1.1"
1706 |
1707 | posthtml-render@^3.0.0:
1708 | version "3.0.0"
1709 | resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205"
1710 | integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==
1711 | dependencies:
1712 | is-json "^2.0.1"
1713 |
1714 | posthtml@^0.16.4, posthtml@^0.16.5:
1715 | version "0.16.6"
1716 | resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.6.tgz#e2fc407f67a64d2fa3567afe770409ffdadafe59"
1717 | integrity sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==
1718 | dependencies:
1719 | posthtml-parser "^0.11.0"
1720 | posthtml-render "^3.0.0"
1721 |
1722 | progress@2.0.3:
1723 | version "2.0.3"
1724 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
1725 | integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
1726 |
1727 | proxy-from-env@1.1.0:
1728 | version "1.1.0"
1729 | resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
1730 | integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
1731 |
1732 | pump@^3.0.0:
1733 | version "3.0.0"
1734 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
1735 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
1736 | dependencies:
1737 | end-of-stream "^1.1.0"
1738 | once "^1.3.1"
1739 |
1740 | puppeteer@^13.0.0:
1741 | version "13.7.0"
1742 | resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-13.7.0.tgz#18e16f83e397cf02f7a0804c67c1603d381cfb0b"
1743 | integrity sha512-U1uufzBjz3+PkpCxFrWzh4OrMIdIb2ztzCu0YEPfRHjHswcSwHZswnK+WdsOQJsRV8WeTg3jLhJR4D867+fjsA==
1744 | dependencies:
1745 | cross-fetch "3.1.5"
1746 | debug "4.3.4"
1747 | devtools-protocol "0.0.981744"
1748 | extract-zip "2.0.1"
1749 | https-proxy-agent "5.0.1"
1750 | pkg-dir "4.2.0"
1751 | progress "2.0.3"
1752 | proxy-from-env "1.1.0"
1753 | rimraf "3.0.2"
1754 | tar-fs "2.1.1"
1755 | unbzip2-stream "1.4.3"
1756 | ws "8.5.0"
1757 |
1758 | react-error-overlay@6.0.9:
1759 | version "6.0.9"
1760 | resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
1761 | integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
1762 |
1763 | react-refresh@^0.9.0:
1764 | version "0.9.0"
1765 | resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf"
1766 | integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==
1767 |
1768 | readable-stream@^3.1.1, readable-stream@^3.4.0:
1769 | version "3.6.2"
1770 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
1771 | integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
1772 | dependencies:
1773 | inherits "^2.0.3"
1774 | string_decoder "^1.1.1"
1775 | util-deprecate "^1.0.1"
1776 |
1777 | regenerator-runtime@^0.13.7:
1778 | version "0.13.11"
1779 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
1780 | integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
1781 |
1782 | resolve-from@^4.0.0:
1783 | version "4.0.0"
1784 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
1785 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
1786 |
1787 | rimraf@3.0.2:
1788 | version "3.0.2"
1789 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
1790 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
1791 | dependencies:
1792 | glob "^7.1.3"
1793 |
1794 | safe-buffer@^5.0.1, safe-buffer@~5.2.0:
1795 | version "5.2.1"
1796 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
1797 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
1798 |
1799 | semver@^7.5.2:
1800 | version "7.5.3"
1801 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
1802 | integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
1803 | dependencies:
1804 | lru-cache "^6.0.0"
1805 |
1806 | shortcuts@^2.0.3:
1807 | version "2.0.3"
1808 | resolved "https://registry.yarnpkg.com/shortcuts/-/shortcuts-2.0.3.tgz#fca8ef10efc765a9a71844362ac1342036e8aa9c"
1809 | integrity sha512-8Cjrzz15LBDmknBokvY8aWoyjc4U2CdbmhU4Jg5axi8jpD0wlFUjqKMAdMU0DkOpVp64vn3ISxngAg3WmpUa5g==
1810 |
1811 | source-map@^0.6.1:
1812 | version "0.6.1"
1813 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
1814 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
1815 |
1816 | srcset@4:
1817 | version "4.0.0"
1818 | resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4"
1819 | integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==
1820 |
1821 | stable@^0.1.8:
1822 | version "0.1.8"
1823 | resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
1824 | integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
1825 |
1826 | string_decoder@^1.1.1:
1827 | version "1.3.0"
1828 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
1829 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
1830 | dependencies:
1831 | safe-buffer "~5.2.0"
1832 |
1833 | supports-color@^5.3.0:
1834 | version "5.5.0"
1835 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
1836 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
1837 | dependencies:
1838 | has-flag "^3.0.0"
1839 |
1840 | supports-color@^7.1.0:
1841 | version "7.2.0"
1842 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
1843 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
1844 | dependencies:
1845 | has-flag "^4.0.0"
1846 |
1847 | svgo@^2.4.0:
1848 | version "2.8.0"
1849 | resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
1850 | integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
1851 | dependencies:
1852 | "@trysound/sax" "0.2.0"
1853 | commander "^7.2.0"
1854 | css-select "^4.1.3"
1855 | css-tree "^1.1.3"
1856 | csso "^4.2.0"
1857 | picocolors "^1.0.0"
1858 | stable "^0.1.8"
1859 |
1860 | tar-fs@2.1.1:
1861 | version "2.1.1"
1862 | resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
1863 | integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
1864 | dependencies:
1865 | chownr "^1.1.1"
1866 | mkdirp-classic "^0.5.2"
1867 | pump "^3.0.0"
1868 | tar-stream "^2.1.4"
1869 |
1870 | tar-stream@^2.1.4:
1871 | version "2.2.0"
1872 | resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
1873 | integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
1874 | dependencies:
1875 | bl "^4.0.3"
1876 | end-of-stream "^1.4.1"
1877 | fs-constants "^1.0.0"
1878 | inherits "^2.0.3"
1879 | readable-stream "^3.1.1"
1880 |
1881 | term-size@^2.2.1:
1882 | version "2.2.1"
1883 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
1884 | integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==
1885 |
1886 | through@^2.3.8:
1887 | version "2.3.8"
1888 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
1889 | integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
1890 |
1891 | timsort@^0.3.0:
1892 | version "0.3.0"
1893 | resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
1894 | integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==
1895 |
1896 | tinykeys@^2.1.0:
1897 | version "2.1.0"
1898 | resolved "https://registry.yarnpkg.com/tinykeys/-/tinykeys-2.1.0.tgz#1341563e92a7fac9ca90053fddaf2b7553500298"
1899 | integrity sha512-/MESnqBD1xItZJn5oGQ4OsNORQgJfPP96XSGoyu4eLpwpL0ifO0SYR5OD76u0YMhMXsqkb0UqvI9+yXTh4xv8Q==
1900 |
1901 | to-regex-range@^5.0.1:
1902 | version "5.0.1"
1903 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
1904 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
1905 | dependencies:
1906 | is-number "^7.0.0"
1907 |
1908 | tr46@~0.0.3:
1909 | version "0.0.3"
1910 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
1911 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
1912 |
1913 | ts-node@^10.9.1:
1914 | version "10.9.1"
1915 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
1916 | integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
1917 | dependencies:
1918 | "@cspotcode/source-map-support" "^0.8.0"
1919 | "@tsconfig/node10" "^1.0.7"
1920 | "@tsconfig/node12" "^1.0.7"
1921 | "@tsconfig/node14" "^1.0.0"
1922 | "@tsconfig/node16" "^1.0.2"
1923 | acorn "^8.4.1"
1924 | acorn-walk "^8.1.1"
1925 | arg "^4.1.0"
1926 | create-require "^1.1.0"
1927 | diff "^4.0.1"
1928 | make-error "^1.1.1"
1929 | v8-compile-cache-lib "^3.0.1"
1930 | yn "3.1.1"
1931 |
1932 | tslib@^2.4.0, tslib@^2.6.0:
1933 | version "2.6.0"
1934 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3"
1935 | integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==
1936 |
1937 | type-fest@^0.20.2:
1938 | version "0.20.2"
1939 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
1940 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
1941 |
1942 | typescript@^5.1.6:
1943 | version "5.1.6"
1944 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
1945 | integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
1946 |
1947 | unbzip2-stream@1.4.3:
1948 | version "1.4.3"
1949 | resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7"
1950 | integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==
1951 | dependencies:
1952 | buffer "^5.2.1"
1953 | through "^2.3.8"
1954 |
1955 | update-browserslist-db@^1.0.11:
1956 | version "1.0.11"
1957 | resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940"
1958 | integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==
1959 | dependencies:
1960 | escalade "^3.1.1"
1961 | picocolors "^1.0.0"
1962 |
1963 | util-deprecate@^1.0.1:
1964 | version "1.0.2"
1965 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
1966 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
1967 |
1968 | utility-types@^3.10.0:
1969 | version "3.10.0"
1970 | resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
1971 | integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
1972 |
1973 | v8-compile-cache-lib@^3.0.1:
1974 | version "3.0.1"
1975 | resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
1976 | integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
1977 |
1978 | weak-lru-cache@^1.2.2:
1979 | version "1.2.2"
1980 | resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz#fdbb6741f36bae9540d12f480ce8254060dccd19"
1981 | integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==
1982 |
1983 | webidl-conversions@^3.0.0:
1984 | version "3.0.1"
1985 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
1986 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
1987 |
1988 | whatwg-url@^5.0.0:
1989 | version "5.0.0"
1990 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
1991 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
1992 | dependencies:
1993 | tr46 "~0.0.3"
1994 | webidl-conversions "^3.0.0"
1995 |
1996 | wrappy@1:
1997 | version "1.0.2"
1998 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
1999 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
2000 |
2001 | ws@8.5.0:
2002 | version "8.5.0"
2003 | resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
2004 | integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
2005 |
2006 | xxhash-wasm@^0.4.2:
2007 | version "0.4.2"
2008 | resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79"
2009 | integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==
2010 |
2011 | yallist@^4.0.0:
2012 | version "4.0.0"
2013 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
2014 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
2015 |
2016 | yauzl@^2.10.0:
2017 | version "2.10.0"
2018 | resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
2019 | integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==
2020 | dependencies:
2021 | buffer-crc32 "~0.2.3"
2022 | fd-slicer "~1.1.0"
2023 |
2024 | yn@3.1.1:
2025 | version "3.1.1"
2026 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
2027 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
2028 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'ts-jest',
3 | testEnvironment: 'jsdom',
4 | coverageDirectory: './coverage',
5 | coverageReporters: ['lcov'],
6 | testPathIgnorePatterns: ['/node_modules/', '/benchmarks/', '/tmp/'],
7 | }
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ctrl-keys",
3 | "version": "1.0.6",
4 | "author": "Amine Ben hammou",
5 | "description": "A tiny, super fast, typescript library to handle keybindings efficiently.",
6 | "keywords": [
7 | "typescript",
8 | "keybindings",
9 | "keyboard-shortcuts",
10 | "keyboard-events"
11 | ],
12 | "license": "MIT",
13 | "source": "src/index.ts",
14 | "main": "dist/index.js",
15 | "module": "dist/index.mjs",
16 | "types": "dist/index.d.ts",
17 | "exports": {
18 | ".": {
19 | "types": "./dist/index.d.ts",
20 | "import": "./dist/index.mjs",
21 | "require": "./dist/index.js",
22 | "default": "./dist/index.js"
23 | }
24 | },
25 | "files": [
26 | "dist"
27 | ],
28 | "engines": {
29 | "node": ">=10"
30 | },
31 | "scripts": {
32 | "bench": "cd benchmark && yarn && yarn build",
33 | "build": "tsup",
34 | "test": "jest",
35 | "test-coverage": "jest --coverage"
36 | },
37 | "devDependencies": {
38 | "@testing-library/dom": "^10.4.0",
39 | "@testing-library/user-event": "^14.6.1",
40 | "@types/jest": "^29.5.14",
41 | "jest": "^29.7.0",
42 | "jest-environment-jsdom": "^29.7.0",
43 | "just-types": "^2.0.0-alpha.3",
44 | "ts-jest": "^29.2.5",
45 | "tslib": "^2.8.1",
46 | "tsup": "8.0.1",
47 | "typescript": "^5.7.3"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/screenshots/keys-autocomplete.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/webNeat/ctrl-keys/c052ec38216967d54c59fb747e8df3cce13d8dd2/screenshots/keys-autocomplete.gif
--------------------------------------------------------------------------------
/src/Handler.test.ts:
--------------------------------------------------------------------------------
1 | import {fnMocks} from './test-utils'
2 | import {Handler} from './Handler'
3 | import {createEvent} from './event'
4 |
5 | describe('Handler', () => {
6 | const handler = new Handler({
7 | history: [],
8 | historySize: 0,
9 | bindings: new Map(),
10 | disabledSequenceCodes: new Set(),
11 | })
12 |
13 | const fns = fnMocks('ctrl+a1', 'ctrl+a2', 'ctrl+alt ctrl+plus', 'ctrl+shift+space c')
14 |
15 | it(`adds bindings`, () => {
16 | handler.add('ctrl+a', fns.get('ctrl+a1'))
17 | handler.add('ctrl+a', fns.get('ctrl+a2'))
18 |
19 | handler.handle(createEvent('ctrl+a'))
20 | fns.call('ctrl+a1', 'ctrl+a2').checkCalls()
21 |
22 | handler.handle(createEvent('ctrl+b'))
23 | fns.checkCalls()
24 | })
25 |
26 | it(`removes bindings`, () => {
27 | handler.remove('ctrl+a', fns.get('ctrl+a2'))
28 |
29 | handler.handle(createEvent('ctrl+a'))
30 | fns.call('ctrl+a1').checkCalls()
31 | })
32 |
33 | it(`handles multi-keys sequences`, () => {
34 | handler.add('ctrl+alt', 'ctrl+plus', fns.get('ctrl+alt ctrl+plus'))
35 | handler.add('ctrl+shift+space', 'c', fns.get('ctrl+shift+space c'))
36 |
37 | handler.handle(createEvent('ctrl+alt'))
38 | handler.handle(createEvent('ctrl++'))
39 | fns.call('ctrl+alt ctrl+plus').checkCalls()
40 |
41 | handler.handle(createEvent('ctrl+shift+ '))
42 | handler.handle(createEvent('c'))
43 | fns.call('ctrl+shift+space c').checkCalls()
44 | })
45 | })
46 |
--------------------------------------------------------------------------------
/src/Handler.ts:
--------------------------------------------------------------------------------
1 | import {Callback, HandlerInterface, State, Binding, Sequence} from './types'
2 | import {addBinding, disableSequence, enableSequence, handleEvent, removeBinding} from './state'
3 |
4 | export class Handler implements HandlerInterface {
5 | constructor(protected state: State) {
6 | this.add = this.add.bind(this)
7 | this.remove = this.remove.bind(this)
8 | this.handle = this.handle.bind(this)
9 | }
10 |
11 | add(...args: Binding): this {
12 | const keys = args.slice(0, -1) as Sequence
13 | const fn = args.at(-1) as Callback
14 | this.state = addBinding(this.state, keys, fn)
15 | return this
16 | }
17 |
18 | remove(...args: Binding): this {
19 | const keys = args.slice(0, -1) as Sequence
20 | const fn = args.at(-1) as Callback
21 | this.state = removeBinding(this.state, keys, fn)
22 | return this
23 | }
24 |
25 | enable(...keys: Sequence): this {
26 | this.state = enableSequence(this.state, keys)
27 | return this
28 | }
29 |
30 | disable(...keys: Sequence): this {
31 | this.state = disableSequence(this.state, keys)
32 | return this
33 | }
34 |
35 | handle(event: KeyboardEvent) {
36 | const [state, fns] = handleEvent(this.state, event)
37 | this.state = state
38 | return fns.length > 0
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/constants.ts:
--------------------------------------------------------------------------------
1 | import {AliasCharacter, Character} from './types'
2 |
3 | export const modifiers = ['ctrl', 'alt', 'meta', 'shift'] as const
4 |
5 | export const chars =
6 | '__0_1_2_3_4_5_6_7_8_9_a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z_ _`_\'_"_~_!_@_#_$_%_^_&_*_(_)_._-_+_=_[_]_{_}_<_>_,_/_?_;_:_\\_|_capslock_numlock_enter_tab_arrowdown_arrowleft_arrowright_arrowup_end_home_pagedown_pageup_backspace_delete_insert_escape_f1_f2_f3_f4_f5_f6_f7_f8_f9_f10_f11_f12_f13_f14_f15_f16_f17_f18_f19_f20_f21_f22_f23'.split(
7 | '_'
8 | )
9 | chars[1] = '_'
10 |
11 | export const codes: Record = {}
12 | for (const [i, c] of chars.entries()) codes[c] = i
13 |
14 | export const aliases: Record = {
15 | space: ' ',
16 | plus: '+',
17 | up: 'arrowup',
18 | down: 'arrowdown',
19 | left: 'arrowleft',
20 | right: 'arrowright',
21 | esc: 'escape',
22 | }
23 |
24 | /**
25 | We want to encode keys and sequences of keys as numbers for performance
26 | A key code is 13 bits: XXXXXXXXXCAMS
27 | XXXXXXXXX: 9 bits representing the character (event.key value).
28 | A character can't have a code `0`, that's a special value.
29 | We can have at most 511 different characters!
30 | CAMS: 4 bits representing the modifiers `Ctrl`, `Alt`, `Meta` and `Shift` in this order.
31 | A sequence of keys is represented by the concatenation of codes of the keys.
32 | An integer can safely be represented with 53 bits in Javascript `Number.MAX_SAFE_INTEGER`
33 | Since every key takes 13bits, a sequence can at most contain 4 keys = 52 bits!
34 | */
35 |
36 | export const MODIFIERS_SIZE = 4
37 | export const CHARACTER_SIZE = 9
38 | export const CTRL_MASK = 0b1000
39 | export const ALT_MASK = 0b0100
40 | export const META_MASK = 0b0010
41 | export const SHIFT_MASK = 0b0001
42 | export const KEY_SIZE = CHARACTER_SIZE + MODIFIERS_SIZE
43 | export const MODIFIERS_UPPER_BOUND = 2 ** MODIFIERS_SIZE
44 | export const ONE_KEY_UPPER_BOUND = 2 ** KEY_SIZE
45 | export const TWO_KEYS_UPPER_BOUND = 2 ** (2 * KEY_SIZE)
46 | export const THREE_KEYS_UPPER_BOUND = 2 ** (3 * KEY_SIZE)
47 |
--------------------------------------------------------------------------------
/src/event.test.ts:
--------------------------------------------------------------------------------
1 | import {encodeEvent, createEvent} from './event'
2 | import {encode} from './test-utils'
3 |
4 | describe('createEvent', () => {
5 | const expectEventsEqual = (event: KeyboardEvent, type: string, data: Partial) => {
6 | const expectedEvent = new KeyboardEvent(type, {ctrlKey: false, altKey: false, metaKey: false, shiftKey: false, ...data})
7 | expect(event).toBeInstanceOf(KeyboardEvent)
8 | expect(event.type).toBe(type)
9 | expect(event.ctrlKey).toBe(expectedEvent.ctrlKey)
10 | expect(event.altKey).toBe(expectedEvent.altKey)
11 | expect(event.metaKey).toBe(expectedEvent.metaKey)
12 | expect(event.shiftKey).toBe(expectedEvent.shiftKey)
13 | expect(event.key).toBe(expectedEvent.key)
14 | }
15 |
16 | it('creates an event without modifiers', () => {
17 | expectEventsEqual(createEvent('a'), 'keydown', {key: 'a'})
18 | expectEventsEqual(createEvent('up'), 'keydown', {key: 'arrowup'})
19 | expectEventsEqual(createEvent('-', 'keyup'), 'keyup', {key: '-'})
20 | expectEventsEqual(createEvent('é' as any), 'keydown', {key: 'é'})
21 | })
22 |
23 | it('creates an event with modifiers', () => {
24 | expectEventsEqual(createEvent('ctrl+a'), 'keydown', {ctrlKey: true, key: 'a'})
25 | expectEventsEqual(createEvent('ctrl+alt'), 'keydown', {ctrlKey: true, altKey: true, key: 'Alt'})
26 | expectEventsEqual(createEvent('ctrl+alt+a', 'keyup'), 'keyup', {ctrlKey: true, altKey: true, key: 'a'})
27 | expectEventsEqual(createEvent('meta+shift+up'), 'keydown', {metaKey: true, shiftKey: true, key: 'arrowup'})
28 | expectEventsEqual(createEvent('alt+é' as any), 'keydown', {altKey: true, key: 'é'})
29 | })
30 | })
31 |
32 | describe('encodeEvent', () => {
33 | it('encodes an event without modifiers', () => {
34 | expect(encodeEvent(createEvent('0'))).toBe(encode('0'))
35 | expect(encodeEvent(createEvent('a'))).toBe(encode('a'))
36 | expect(encodeEvent(createEvent('-'))).toBe(encode('-'))
37 | })
38 | it('encodes an event with modifiers', () => {
39 | expect(encodeEvent(createEvent('ctrl+a'))).toBe(encode('ctrl+a'))
40 | expect(encodeEvent(createEvent('alt+a'))).toBe(encode('alt+a'))
41 | expect(encodeEvent(createEvent('meta+a'))).toBe(encode('meta+a'))
42 | expect(encodeEvent(createEvent('shift+a'))).toBe(encode('shift+a'))
43 |
44 | expect(encodeEvent(createEvent('alt+meta'))).toBe(encode('alt+meta'))
45 | expect(encodeEvent(createEvent('ctrl+meta+a'))).toBe(encode('ctrl+meta+a'))
46 | expect(encodeEvent(createEvent('ctrl+alt+shift+a'))).toBe(encode('ctrl+alt+shift+a'))
47 | expect(encodeEvent(createEvent('ctrl+alt+meta+shift+a'))).toBe(encode('ctrl+alt+meta+shift+a'))
48 | })
49 | it('encodes a modifier key event', () => {
50 | expect(encodeEvent(createEvent('ctrl+alt'))).toBe(encode('ctrl+alt'))
51 | expect(encodeEvent(createEvent('ctrl+alt'))).toBe(encode('ctrl+alt'))
52 | expect(encodeEvent(createEvent('alt+meta'))).toBe(encode('alt+meta'))
53 | })
54 | it('encodes unknown key event', () => {
55 | expect(encodeEvent(createEvent('é' as any))).toBe(0)
56 | expect(encodeEvent(createEvent('ctrl+alt+é' as any))).toBe(encode('ctrl+alt'))
57 | })
58 | })
59 |
--------------------------------------------------------------------------------
/src/event.ts:
--------------------------------------------------------------------------------
1 | import {normalizeKey} from './key'
2 | import {aliases, codes, modifiers} from './constants'
3 | import {AliasCharacter, Character, EncodedKey, Key, KeyboardEventType, Modifier} from './types'
4 |
5 | export function createEvent(key: Key, type: KeyboardEventType = 'keydown') {
6 | const parts = normalizeKey(key) as Array
7 | let eventKey = parts.at(-1) as string
8 | if (aliases[eventKey as AliasCharacter] !== undefined) eventKey = aliases[eventKey as AliasCharacter]
9 | if (eventKey === 'ctrl') eventKey = 'Control'
10 | if (eventKey === 'alt') eventKey = 'Alt'
11 | if (eventKey === 'meta') eventKey = 'Meta'
12 | if (eventKey === 'shift') eventKey = 'Shift'
13 | return new KeyboardEvent(type, {
14 | ctrlKey: parts.includes('ctrl'),
15 | altKey: parts.includes('alt'),
16 | metaKey: parts.includes('meta'),
17 | shiftKey: parts.includes('shift'),
18 | key: eventKey,
19 | })
20 | }
21 |
22 | export function encodeEvent(event: KeyboardEvent): EncodedKey {
23 | let code = codes[event.key.toLowerCase()] || 0
24 | for (const modifier of modifiers) {
25 | code = 2 * code + (event[`${modifier}Key` as keyof KeyboardEvent] ? 1 : 0)
26 | }
27 | return code
28 | }
29 |
--------------------------------------------------------------------------------
/src/index.test.ts:
--------------------------------------------------------------------------------
1 | import keys from '.'
2 | import userEvent from '@testing-library/user-event'
3 |
4 | test('basic usage', async () => {
5 | let counter = 0
6 | const increment = () => (counter += 1)
7 | const decrement = () => (counter -= 1)
8 | const reset = () => (counter = 0)
9 | const handler = keys().add('ctrl+up', increment).add('ctrl+down', decrement).add('esc', reset)
10 | window.addEventListener('keydown', handler.handle)
11 |
12 | await userEvent.keyboard('{Control>}{ArrowUp}{/Control}')
13 | expect(counter).toBe(1)
14 |
15 | await userEvent.keyboard('{Control>}{ArrowUp}{ArrowUp}{ArrowUp}{ArrowUp}{/Control}')
16 | expect(counter).toBe(5)
17 |
18 | await userEvent.keyboard('{Control>}{ArrowDown}{ArrowDown}{ArrowDown}{/Control}')
19 | expect(counter).toBe(2)
20 |
21 | await userEvent.keyboard('{ArrowUp}')
22 | expect(counter).toBe(2)
23 |
24 | handler.disable('ctrl+up')
25 | await userEvent.keyboard('{Control>}{ArrowUp}{ArrowUp}{ArrowUp}{ArrowUp}{/Control}')
26 | expect(counter).toBe(2)
27 |
28 | handler.enable('ctrl+up')
29 | await userEvent.keyboard('{Control>}{ArrowUp}{ArrowUp}{ArrowUp}{/Control}')
30 | expect(counter).toBe(5)
31 |
32 | handler.remove('ctrl+up', increment)
33 | await userEvent.keyboard('{Control>}{ArrowUp}{ArrowUp}{ArrowUp}{ArrowUp}{/Control}')
34 | expect(counter).toBe(5)
35 |
36 | handler.add('ctrl+up', increment)
37 | await userEvent.keyboard('{Control>}{ArrowUp}{ArrowUp}{/Control}')
38 | expect(counter).toBe(7)
39 |
40 | await userEvent.keyboard('{Escape}')
41 | expect(counter).toBe(0)
42 |
43 | window.removeEventListener('keydown', handler.handle)
44 | await userEvent.keyboard('{Control>}{ArrowUp}{ArrowUp}{ArrowUp}{ArrowUp}{/Control}')
45 | expect(counter).toBe(0)
46 | })
47 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import {Handler} from './Handler'
2 | import {createState} from './state'
3 |
4 | export * from './types'
5 |
6 | export function keys() {
7 | return new Handler(createState())
8 | }
9 |
10 | export default keys
11 |
--------------------------------------------------------------------------------
/src/key.test.ts:
--------------------------------------------------------------------------------
1 | import {codes} from './constants'
2 | import {decodeKey, encodeKey, getCharacterCode, getModifiersCode, normalizeKey, shouldOverride} from './key'
3 | import {NormalizedKey} from './types'
4 |
5 | describe('normalizeKey', () => {
6 | it(`handles keys without modifiers`, () => {
7 | expect(normalizeKey('a')).toEqual(['a'])
8 | expect(normalizeKey('.')).toEqual(['.'])
9 | expect(normalizeKey('+')).toEqual(['+'])
10 | expect(normalizeKey(' ')).toEqual([' '])
11 | expect(normalizeKey('enter')).toEqual(['enter'])
12 | })
13 | it(`handles keys with modifiers`, () => {
14 | expect(normalizeKey('ctrl+a')).toEqual(['ctrl', 'a'])
15 | expect(normalizeKey('alt+.')).toEqual(['alt', '.'])
16 | expect(normalizeKey('meta++')).toEqual(['meta', '+'])
17 | expect(normalizeKey('shift+ ')).toEqual(['shift', ' '])
18 | expect(normalizeKey('ctrl+alt+enter')).toEqual(['ctrl', 'alt', 'enter'])
19 | expect(normalizeKey('ctrl+alt++')).toEqual(['ctrl', 'alt', '+'])
20 | })
21 | it(`applies aliases`, () => {
22 | expect(normalizeKey('ctrl+up')).toEqual(['ctrl', 'arrowup'])
23 | expect(normalizeKey('ctrl+alt+space')).toEqual(['ctrl', 'alt', ' '])
24 | expect(normalizeKey('ctrl+alt+plus')).toEqual(['ctrl', 'alt', '+'])
25 | })
26 | })
27 |
28 | describe('encodeKey', () => {
29 | it('encodes a key without modifiers', () => {
30 | expect(encodeKey(['0'])).toBe(codes['0'] << 4)
31 | expect(encodeKey(['a'])).toBe(codes['a'] << 4)
32 | expect(encodeKey(['-'])).toBe(codes['-'] << 4)
33 | })
34 | it('encodes a key with modifiers', () => {
35 | expect(encodeKey(['ctrl', 'a'])).toBe((codes['a'] << 4) + 0b1000)
36 | expect(encodeKey(['alt', 'a'])).toBe((codes['a'] << 4) + 0b0100)
37 | expect(encodeKey(['meta', 'a'])).toBe((codes['a'] << 4) + 0b0010)
38 | expect(encodeKey(['shift', 'a'])).toBe((codes['a'] << 4) + 0b0001)
39 |
40 | expect(encodeKey(['ctrl', '-'])).toBe((codes['-'] << 4) + 0b1000)
41 | expect(encodeKey(['alt', '-'])).toBe((codes['-'] << 4) + 0b0100)
42 | expect(encodeKey(['meta', '-'])).toBe((codes['-'] << 4) + 0b0010)
43 | expect(encodeKey(['shift', '-'])).toBe((codes['-'] << 4) + 0b0001)
44 |
45 | expect(encodeKey(['ctrl', 'alt', 'shift', 'a'])).toBe((codes['a'] << 4) + 0b1101)
46 | expect(encodeKey(['alt', 'meta', 'a'])).toBe((codes['a'] << 4) + 0b0110)
47 | expect(encodeKey(['ctrl', 'meta', 'a'])).toBe((codes['a'] << 4) + 0b1010)
48 | expect(encodeKey(['ctrl', 'alt', 'meta', 'shift', 'a'])).toBe((codes['a'] << 4) + 0b1111)
49 | })
50 | it('encodes a modifier key', () => {
51 | expect(encodeKey(['ctrl', 'alt'])).toBe(0b1100)
52 | expect(encodeKey(['alt', 'meta'])).toBe(0b0110)
53 | })
54 | it('encodes unknown key', () => {
55 | expect(encodeKey(['é' as any])).toBe(0)
56 | expect(encodeKey(['ctrl', 'alt', 'é' as any])).toBe(0b1100)
57 | })
58 | })
59 |
60 | describe('decodeKey', () => {
61 | it('decodes keys', () => {
62 | const keys: NormalizedKey[] = [['a'], ['-'], ['ctrl'], ['ctrl', 'alt', 'a'], ['ctrl', 'alt', 'meta']]
63 | for (const key of keys) {
64 | expect(decodeKey(encodeKey(key))).toEqual(key)
65 | }
66 | })
67 | })
68 |
69 | describe('getCharacterCode', () => {
70 | it('extracts the character code from a key code without modifiers', () => {
71 | expect(getCharacterCode(0b01011100000)).toBe(0b0101110)
72 | expect(getCharacterCode(0b10000)).toBe(0b1)
73 | })
74 | it('extracts the character code from a key code with modifiers', () => {
75 | expect(getCharacterCode(0b01011100110)).toBe(0b0101110)
76 | expect(getCharacterCode(0b10101)).toBe(0b1)
77 | })
78 | })
79 |
80 | describe('getModifiersCode', () => {
81 | it('extracts the modifiers code from a key code', () => {
82 | expect(getModifiersCode(0b01011100000)).toBe(0b0)
83 | expect(getModifiersCode(0b01011100110)).toBe(0b0110)
84 | expect(getModifiersCode(0b10101)).toBe(0b0101)
85 | })
86 | })
87 |
88 | describe('shouldOverride', () => {
89 | it('returns false if no previous key', () => {
90 | expect(shouldOverride(undefined, encodeKey(['a']))).toBe(false)
91 | expect(shouldOverride(undefined, encodeKey(['ctrl']))).toBe(false)
92 | expect(shouldOverride(undefined, encodeKey(['alt', 'b']))).toBe(false)
93 | })
94 | it('returns false if previous key already has a character', () => {
95 | expect(shouldOverride(encodeKey(['a']), encodeKey(['a']))).toBe(false)
96 | expect(shouldOverride(encodeKey(['a']), encodeKey(['b']))).toBe(false)
97 | expect(shouldOverride(encodeKey(['a']), encodeKey(['meta', 'a']))).toBe(false)
98 | expect(shouldOverride(encodeKey(['meta', 'a']), encodeKey(['alt', 'meta', 'a']))).toBe(false)
99 | expect(shouldOverride(encodeKey(['meta', 'a']), encodeKey(['meta']))).toBe(false)
100 | expect(shouldOverride(encodeKey(['meta', 'a']), encodeKey(['ctrl']))).toBe(false)
101 | })
102 | it('returns false if previous key has a modifier that is missing on the new key', () => {
103 | expect(shouldOverride(encodeKey(['ctrl']), encodeKey(['alt']))).toBe(false)
104 | expect(shouldOverride(encodeKey(['ctrl', 'alt']), encodeKey(['alt']))).toBe(false)
105 | expect(shouldOverride(encodeKey(['ctrl', 'alt']), encodeKey(['alt', 'a']))).toBe(false)
106 | })
107 | it('returns false if previous key equals the new key', () => {
108 | expect(shouldOverride(encodeKey(['ctrl']), encodeKey(['ctrl']))).toBe(false)
109 | expect(shouldOverride(encodeKey(['ctrl', 'alt']), encodeKey(['ctrl', 'alt']))).toBe(false)
110 | })
111 | it('returns true if the previous key has only modifiers and the new key adds a modifier or a character to them', () => {
112 | expect(shouldOverride(encodeKey(['ctrl']), encodeKey(['ctrl', 'a']))).toBe(true)
113 | expect(shouldOverride(encodeKey(['ctrl']), encodeKey(['ctrl', 'alt']))).toBe(true)
114 | expect(shouldOverride(encodeKey(['alt']), encodeKey(['ctrl', 'alt']))).toBe(true)
115 | expect(shouldOverride(encodeKey(['ctrl', 'alt']), encodeKey(['ctrl', 'alt', 'a']))).toBe(true)
116 | })
117 | })
118 |
--------------------------------------------------------------------------------
/src/key.ts:
--------------------------------------------------------------------------------
1 | import {aliases, ALT_MASK, chars, codes, CTRL_MASK, META_MASK, modifiers, MODIFIERS_SIZE, MODIFIERS_UPPER_BOUND, SHIFT_MASK} from './constants'
2 | import {EncodedKey, Key, NormalizedKey} from './types'
3 |
4 | export function normalizeKey(key: Key): NormalizedKey {
5 | let parts: string[]
6 | if (key === '+') return ['+']
7 | if ('+' == key.slice(-1)) {
8 | parts = key.slice(0, -2).split('+')
9 | parts.push('+')
10 | } else {
11 | parts = key.split('+')
12 | }
13 | return parts.map((x) => (aliases as any)[x] || x) as NormalizedKey
14 | }
15 |
16 | export function encodeKey(key: NormalizedKey): EncodedKey {
17 | const parts = new Set(key)
18 | let code = codes[key[key.length - 1].toLowerCase()] || 0
19 | for (const modifier of modifiers) {
20 | code = 2 * code + (parts.has(modifier) ? 1 : 0)
21 | }
22 | return code
23 | }
24 |
25 | export function decodeKey(encodedKey: EncodedKey): NormalizedKey {
26 | const charCode = getCharacterCode(encodedKey)
27 | const modifiersCode = getModifiersCode(encodedKey)
28 | const key = []
29 | if (modifiersCode & CTRL_MASK) key.push('ctrl')
30 | if (modifiersCode & ALT_MASK) key.push('alt')
31 | if (modifiersCode & META_MASK) key.push('meta')
32 | if (modifiersCode & SHIFT_MASK) key.push('shift')
33 | const c = chars[charCode]
34 | if (c) key.push(c)
35 | return key as any
36 | }
37 |
38 | export function getCharacterCode(encodedKey: EncodedKey) {
39 | return encodedKey >> MODIFIERS_SIZE
40 | }
41 |
42 | export function getModifiersCode(encodedKey: EncodedKey) {
43 | return encodedKey % MODIFIERS_UPPER_BOUND
44 | }
45 |
46 | export function shouldOverride(previousKey: EncodedKey | undefined, newKey: EncodedKey) {
47 | if (previousKey === undefined) return false
48 | if (getCharacterCode(previousKey) > 0) return false
49 | const previousModifiers = getModifiersCode(previousKey)
50 | const newModifiers = getModifiersCode(newKey)
51 | if (previousModifiers === newModifiers && getCharacterCode(newKey) === 0) return false
52 | return (previousModifiers & getModifiersCode(newKey)) === previousModifiers
53 | }
54 |
--------------------------------------------------------------------------------
/src/sequence.test.ts:
--------------------------------------------------------------------------------
1 | import {Character, NormalizedSequence} from './types'
2 | import {codes} from './constants'
3 | import {encode} from './test-utils'
4 | import {decodeSequence, encodeSequence, getEncodedSequencesFromHistory, getSequenceSize, normalizeSequence} from './sequence'
5 |
6 | describe('normalizeSequence', () => {
7 | it(`normalizes many keys`, () => {
8 | expect(normalizeSequence(['ctrl+up', 'alt+tab', 'ctrl+alt+space', 'ctrl+alt+plus'])).toEqual([
9 | ['ctrl', 'arrowup'],
10 | ['alt', 'tab'],
11 | ['ctrl', 'alt', ' '],
12 | ['ctrl', 'alt', '+'],
13 | ])
14 | })
15 | })
16 |
17 | describe('encodeSequence', () => {
18 | const bin = (c: Character) => codes[c].toString(2).padStart(9, '0')
19 | const asInt = (text: string) => parseInt(text, 2)
20 |
21 | it('encodes single key sequence', () => {
22 | expect(encodeSequence([['0']])).toBe(asInt(bin('0') + '0000'))
23 | expect(encodeSequence([['ctrl', 'a']])).toBe(asInt(bin('a') + '1000'))
24 | expect(encodeSequence([['alt', 'meta', '-']])).toBe(asInt(bin('-') + '0110'))
25 | })
26 | it('encodes multiple keys sequence', () => {
27 | const ctrlA = bin('a') + '1000'
28 | const metaA = bin('a') + '0010'
29 | const shiftA = bin('a') + '0001'
30 | const altDash = bin('-') + '0100'
31 | expect(
32 | encodeSequence([
33 | ['ctrl', 'a'],
34 | ['alt', '-'],
35 | ])
36 | ).toBe(asInt(ctrlA + altDash))
37 | expect(
38 | encodeSequence([
39 | ['meta', 'a'],
40 | ['shift', 'a'],
41 | ])
42 | ).toBe(asInt(metaA + shiftA))
43 | expect(
44 | encodeSequence([
45 | ['alt', '-'],
46 | ['meta', 'a'],
47 | ['shift', 'a'],
48 | ])
49 | ).toBe(asInt(altDash + metaA + shiftA))
50 | expect(
51 | encodeSequence([
52 | ['meta', 'a'],
53 | ['shift', 'a'],
54 | ['ctrl', 'a'],
55 | ['alt', '-'],
56 | ])
57 | ).toBe(asInt(metaA + shiftA + ctrlA + altDash))
58 | })
59 | it('fails if the sequence contains more than 4 keys', () => {
60 | expect(() => encodeSequence([['a'], ['a'], ['a'], ['a'], ['a']])).toThrow(`Can't encode sequence of more than 4 keys!`)
61 | })
62 | })
63 |
64 | describe('decodeSequence', () => {
65 | it('decodes sequences', () => {
66 | const sequences: NormalizedSequence[] = [
67 | [['a'], ['-']],
68 | [['ctrl', 'a'], ['-']],
69 | [['ctrl']],
70 | [['ctrl'], ['a']],
71 | [
72 | ['ctrl', 'alt', 'a'],
73 | ['ctrl', 'alt', 'meta'],
74 | ],
75 | ]
76 | for (const seq of sequences) {
77 | expect(decodeSequence(encodeSequence(seq))).toEqual(seq)
78 | }
79 | })
80 | })
81 |
82 | describe('getSequenceSize', () => {
83 | it('gets the number of keys on a sequence', () => {
84 | expect(getSequenceSize(encodeSequence([['ctrl', 'a']]))).toBe(1)
85 | expect(
86 | getSequenceSize(
87 | encodeSequence([
88 | ['ctrl', 'a'],
89 | ['alt', '-'],
90 | ])
91 | )
92 | ).toBe(2)
93 | expect(getSequenceSize(encodeSequence([['ctrl', 'a'], ['-'], ['alt', '-']]))).toBe(3)
94 | expect(getSequenceSize(encodeSequence([['ctrl', 'a'], ['a'], ['alt', '-'], ['0']]))).toBe(4)
95 | })
96 | })
97 |
98 | describe('getEncodedSequencesFromHistory', () => {
99 | it(`returns an empty array if the history is empty`, () => {
100 | expect(getEncodedSequencesFromHistory([])).toEqual([])
101 | })
102 | it(`returns a single code if the history contains one item`, () => {
103 | const ctrlA = encode('ctrl+a')
104 | expect(getEncodedSequencesFromHistory([ctrlA])).toEqual([ctrlA])
105 | })
106 | it(`returns a multiple codes if the history contains many items`, () => {
107 | const history = [encode('ctrl'), encode('alt+a'), encode('alt+enter')]
108 | const seqs = [encode('alt+enter'), encode('alt+a', 'alt+enter'), encode('ctrl', 'alt+a', 'alt+enter')]
109 | expect(getEncodedSequencesFromHistory(history)).toEqual(seqs)
110 | })
111 | })
112 |
--------------------------------------------------------------------------------
/src/sequence.ts:
--------------------------------------------------------------------------------
1 | import {ONE_KEY_UPPER_BOUND, THREE_KEYS_UPPER_BOUND, TWO_KEYS_UPPER_BOUND} from './constants'
2 | import {decodeKey, encodeKey, normalizeKey} from './key'
3 | import {EncodedKey, EncodedSequence, NormalizedSequence, Sequence} from './types'
4 |
5 | export function normalizeSequence(sequence: Sequence): NormalizedSequence {
6 | return sequence.map(normalizeKey)
7 | }
8 |
9 | export function encodeSequence(sequence: NormalizedSequence): EncodedSequence {
10 | if (sequence.length > 4) throw `Can't encode sequence of more than 4 keys!`
11 | let code = 0
12 | for (const key of sequence) {
13 | code = code * ONE_KEY_UPPER_BOUND + encodeKey(key)
14 | }
15 | return code
16 | }
17 |
18 | export function decodeSequence(sequence: EncodedSequence): NormalizedSequence {
19 | const keys = []
20 | while (sequence > 0) {
21 | keys.unshift(decodeKey(sequence % 2 ** 13))
22 | sequence = sequence >> 13
23 | }
24 | return keys
25 | }
26 |
27 | export function getSequenceSize(seq: EncodedSequence) {
28 | if (seq < ONE_KEY_UPPER_BOUND) return 1
29 | if (seq < TWO_KEYS_UPPER_BOUND) return 2
30 | if (seq < THREE_KEYS_UPPER_BOUND) return 3
31 | return 4
32 | }
33 |
34 | /*
35 | getEncodedSequencesFromHistory([
36 | keyCode('ctrl+a'),
37 | keyCode('alt+b'),
38 | keyCode('c')
39 | ]) //=> [
40 | seqCode(['c'])
41 | seqCode(['alt+b', 'c'])
42 | seqCode(['ctrl+a', 'alt+b', 'c'])
43 | ]
44 | */
45 | export function getEncodedSequencesFromHistory(keys: EncodedKey[]) {
46 | const result = []
47 | let sequenceCode = 0
48 | let multiplier = 0
49 | for (let i = keys.length - 1; i >= 0; i--) {
50 | sequenceCode = 2 ** multiplier * keys[i] + sequenceCode
51 | multiplier = multiplier + 13
52 | result.push(sequenceCode)
53 | }
54 | return result
55 | }
56 |
--------------------------------------------------------------------------------
/src/state.test.ts:
--------------------------------------------------------------------------------
1 | import {Sequence} from './types'
2 | import {
3 | addBinding,
4 | addEventToHistory,
5 | createState,
6 | disableSequence,
7 | enableSequence,
8 | getMatchingCallbacks,
9 | handleEvent,
10 | removeBinding,
11 | updateHistorySize,
12 | } from './state'
13 | import {bindings, encode, fnMocks} from './test-utils'
14 | import {createEvent} from './event'
15 |
16 | describe('addBinding', () => {
17 | it(`adds a binding to a new key`, () => {
18 | const before = createState()
19 | const sequence: Sequence = ['ctrl+tab']
20 | const fn = () => {}
21 | const after = createState({
22 | historySize: 1,
23 | bindings: bindings([sequence, fn]),
24 | })
25 | expect(addBinding(before, sequence, fn)).toEqual(after)
26 | })
27 |
28 | it(`adds a binding to an existing key`, () => {
29 | const sequence: Sequence = ['ctrl+tab']
30 | const fn1 = () => {}
31 | const before = createState({
32 | historySize: 1,
33 | bindings: bindings([sequence, fn1]),
34 | })
35 |
36 | const fn2 = () => {}
37 | const after = createState({
38 | historySize: 1,
39 | bindings: bindings([sequence, fn1, fn2]),
40 | })
41 | expect(addBinding(before, sequence, fn2)).toEqual(after)
42 | })
43 | })
44 |
45 | describe('removeBinding', () => {
46 | it(`removes a binding from a key`, () => {
47 | const sequence1: Sequence = ['alt+a']
48 | const sequence2: Sequence = ['ctrl', 'meta+ ']
49 | const fn1 = () => {}
50 | const fn2 = () => {}
51 | const fn3 = () => {}
52 | const before = createState({
53 | historySize: 2,
54 | bindings: bindings([sequence1, fn1], [sequence2, fn2, fn3]),
55 | })
56 | const after = createState({
57 | historySize: 2,
58 | bindings: bindings([sequence1, fn1], [sequence2, fn3]),
59 | })
60 | expect(removeBinding(before, sequence2, fn2)).toEqual(after)
61 | })
62 | it(`removes the key if no functions left and updates the historySize`, () => {
63 | const sequence1: Sequence = ['alt+a']
64 | const sequence2: Sequence = ['ctrl', 'meta+ ']
65 | const fn1 = () => {}
66 | const fn2 = () => {}
67 | const before = createState({
68 | historySize: 2,
69 | bindings: bindings([sequence1, fn1], [sequence2, fn2]),
70 | })
71 | const after = createState({
72 | historySize: 1,
73 | bindings: bindings([sequence1, fn1]),
74 | })
75 | expect(removeBinding(before, sequence2, fn2)).toEqual(after)
76 | })
77 | })
78 |
79 | describe('enableSequence', () => {
80 | it('enables a disabled sequence', () => {
81 | const seqCode = encode('ctrl+a', 'alt+b')
82 | let state = createState({
83 | disabledSequenceCodes: new Set([seqCode]),
84 | })
85 | expect(state.disabledSequenceCodes.has(seqCode)).toBe(true)
86 | state = enableSequence(state, ['ctrl+a', 'alt+b'])
87 | expect(state.disabledSequenceCodes.has(seqCode)).toBe(false)
88 | })
89 | it('does nothing if the sequence is not disabled', () => {
90 | const seqCode = encode('ctrl+a', 'alt+b')
91 | let state = createState({
92 | disabledSequenceCodes: new Set([seqCode]),
93 | })
94 | expect(state.disabledSequenceCodes.has(seqCode)).toBe(true)
95 | state = enableSequence(state, ['ctrl+a', 'alt+c'])
96 | expect(state.disabledSequenceCodes.has(seqCode)).toBe(true)
97 | })
98 | })
99 |
100 | describe('disableSequence', () => {
101 | it('disables a sequence', () => {
102 | const seqCode = encode('ctrl+a', 'alt+b')
103 | let state = createState()
104 | expect(state.disabledSequenceCodes.has(seqCode)).toBe(false)
105 | state = disableSequence(state, ['ctrl+a', 'alt+b'])
106 | expect(state.disabledSequenceCodes.has(seqCode)).toBe(true)
107 | })
108 | it('does nothing if the sequence is already disabled', () => {
109 | const seqCode = encode('ctrl+a', 'alt+b')
110 | let state = createState({
111 | disabledSequenceCodes: new Set([seqCode]),
112 | })
113 | state = disableSequence(state, ['ctrl+a', 'alt+b'])
114 | expect(state.disabledSequenceCodes.has(seqCode)).toBe(true)
115 | })
116 | })
117 |
118 | describe('addEventToHistory', () => {
119 | it('adds event to history', () => {
120 | let state = createState({
121 | historySize: 3,
122 | history: [],
123 | })
124 | state = addEventToHistory(state, createEvent('ctrl+up'))
125 | expect(state.history).toEqual([encode('ctrl+up')])
126 | state = addEventToHistory(state, createEvent('ctrl+alt+.'))
127 | expect(state.history).toEqual([encode('ctrl+up'), encode('ctrl+alt+.')])
128 | })
129 |
130 | it('removes the oldest event if size becomes > historySize', () => {
131 | let state = createState({
132 | historySize: 1,
133 | history: [],
134 | })
135 | state = addEventToHistory(state, createEvent('ctrl+up'))
136 | expect(state.history).toEqual([encode('ctrl+up')])
137 | state = addEventToHistory(state, createEvent('ctrl+alt+.'))
138 | expect(state.history).toEqual([encode('ctrl+alt+.')])
139 | })
140 | })
141 |
142 | describe('getMatchingCallbacks', () => {
143 | it('returns the matching callbacks', () => {
144 | const fns = {
145 | 'ctrl+a': () => null,
146 | 'ctrl+alt+a': () => null,
147 | 'ctrl+a ctrl+b': () => null,
148 | 'ctrl ctrl+b': () => null,
149 | }
150 | const state = createState({
151 | bindings: bindings(
152 | [['ctrl+a'], fns['ctrl+a']],
153 | [['ctrl+alt+a'], fns['ctrl+alt+a']],
154 | [['ctrl+a', 'ctrl+b'], fns['ctrl+a ctrl+b']],
155 | [['ctrl', 'ctrl+b'], fns['ctrl ctrl+b']]
156 | ),
157 | })
158 |
159 | state.history = []
160 | expect(getMatchingCallbacks(state)).toEqual([])
161 |
162 | state.history = [encode('a')]
163 | expect(getMatchingCallbacks(state)).toEqual([])
164 |
165 | state.history = [encode('ctrl+a')]
166 | expect(getMatchingCallbacks(state)).toEqual([fns['ctrl+a']])
167 |
168 | state.history = [encode('ctrl+a'), encode('ctrl')]
169 | expect(getMatchingCallbacks(state)).toEqual([])
170 |
171 | state.history = [encode('ctrl+a'), encode('ctrl+b')]
172 | expect(getMatchingCallbacks(state)).toEqual([fns['ctrl+a ctrl+b']])
173 |
174 | state.history = [encode('ctrl+alt+a'), encode('ctrl+b')]
175 | expect(getMatchingCallbacks(state)).toEqual([])
176 |
177 | state.history = [encode('ctrl'), encode('ctrl+b')]
178 | expect(getMatchingCallbacks(state)).toEqual([fns['ctrl ctrl+b']])
179 |
180 | state.history = [encode('ctrl'), encode('ctrl+alt+a')]
181 | expect(getMatchingCallbacks(state)).toEqual([fns['ctrl+alt+a']])
182 | })
183 | })
184 |
185 | describe('handleEvent', () => {
186 | it(`runs matching single key sequence`, () => {
187 | const fns = fnMocks('a', 'alt+b', 'ctrl+a', 'meta')
188 | const theState = createState({
189 | historySize: 1,
190 | bindings: bindings([['a'], fns.get('a')], [['alt+b'], fns.get('alt+b')], [['ctrl+a'], fns.get('ctrl+a')], [['meta'], fns.get('meta')]),
191 | })
192 |
193 | handleEvent(theState, createEvent('a'))
194 | fns.call('a').checkCalls()
195 |
196 | handleEvent(theState, createEvent('ctrl+a'))
197 | fns.call('ctrl+a').checkCalls()
198 |
199 | handleEvent(theState, createEvent('ctrl+b'))
200 | fns.checkCalls()
201 |
202 | handleEvent(theState, createEvent('alt+b'))
203 | fns.call('alt+b').checkCalls()
204 |
205 | handleEvent(theState, createEvent('meta'))
206 | fns.call('meta').checkCalls()
207 |
208 | handleEvent(theState, createEvent('ctrl+meta'))
209 | fns.checkCalls()
210 | })
211 |
212 | it(`runs matching two keys sequence`, () => {
213 | const fns = fnMocks('a ctrl+b', 'ctrl+b alt', 'ctrl alt')
214 | const theState = createState({
215 | historySize: 2,
216 | bindings: bindings(
217 | [['a', 'ctrl+b'], fns.get('a ctrl+b')],
218 | [['ctrl+b', 'alt'], fns.get('ctrl+b alt')],
219 | [['ctrl', 'alt'], fns.get('ctrl alt')]
220 | ),
221 | })
222 |
223 | handleEvent(theState, createEvent('a'))
224 | fns.checkCalls()
225 |
226 | handleEvent(theState, createEvent('ctrl+b'))
227 | fns.call('a ctrl+b').checkCalls()
228 |
229 | handleEvent(theState, createEvent('alt'))
230 | fns.call('ctrl+b alt').checkCalls()
231 |
232 | handleEvent(theState, createEvent('ctrl'))
233 | fns.checkCalls()
234 |
235 | handleEvent(theState, createEvent('alt'))
236 | fns.call('ctrl alt').checkCalls()
237 | })
238 | })
239 |
240 | describe('updateHistorySize', () => {
241 | it(`sets the historySize to the maximum size of sequences`, () => {
242 | const fn = jest.fn()
243 | const theBindings = bindings([['ctrl+a'], fn], [['alt+a', 'meta'], fn], [['meta++', 'arrowup', 'enter'], fn])
244 | const before = createState({historySize: 1, bindings: theBindings})
245 | const after = createState({historySize: 3, bindings: theBindings})
246 | expect(updateHistorySize(before)).toEqual(after)
247 | })
248 | })
249 |
--------------------------------------------------------------------------------
/src/state.ts:
--------------------------------------------------------------------------------
1 | import {encodeEvent} from './event'
2 | import {shouldOverride} from './key'
3 | import {Callback, State, Sequence} from './types'
4 | import {encodeSequence, getEncodedSequencesFromHistory, getSequenceSize, normalizeSequence} from './sequence'
5 |
6 | export function createState(data: Partial = {}): State {
7 | return {
8 | history: [],
9 | historySize: 0,
10 | bindings: new Map(),
11 | disabledSequenceCodes: new Set(),
12 | ...data,
13 | }
14 | }
15 |
16 | export function addBinding(state: State, sequence: Sequence, fn: Callback): State {
17 | const sequenceCode = encodeSequence(normalizeSequence(sequence))
18 | if (!state.bindings.has(sequenceCode)) {
19 | state.bindings.set(sequenceCode, new Set())
20 | }
21 | state.bindings.get(sequenceCode)!.add(fn)
22 | return updateHistorySize(state)
23 | }
24 |
25 | export function removeBinding(state: State, sequence: Sequence, fn: Callback): State {
26 | const sequenceCode = encodeSequence(normalizeSequence(sequence))
27 | const fns = state.bindings.get(sequenceCode)
28 | if (fns) {
29 | fns.delete(fn)
30 | if (fns.size == 0) {
31 | state.bindings.delete(sequenceCode)
32 | }
33 | }
34 | return updateHistorySize(state)
35 | }
36 |
37 | export function enableSequence(state: State, sequence: Sequence): State {
38 | const sequenceCode = encodeSequence(normalizeSequence(sequence))
39 | state.disabledSequenceCodes.delete(sequenceCode)
40 | return state
41 | }
42 |
43 | export function disableSequence(state: State, sequence: Sequence): State {
44 | const sequenceCode = encodeSequence(normalizeSequence(sequence))
45 | state.disabledSequenceCodes.add(sequenceCode)
46 | return state
47 | }
48 |
49 | export function addEventToHistory(state: State, event: KeyboardEvent): State {
50 | const key = encodeEvent(event)
51 | const previousKey = state.history.at(-1)
52 | if (shouldOverride(previousKey, key)) {
53 | state.history.pop()
54 | }
55 | state.history.push(key)
56 | if (state.history.length > state.historySize) {
57 | state.history.shift()
58 | }
59 | return state
60 | }
61 |
62 | export function getMatchingCallbacks(state: State): Callback[] {
63 | const callbacks = []
64 | for (const sequenceCode of getEncodedSequencesFromHistory(state.history)) {
65 | if (state.disabledSequenceCodes.has(sequenceCode)) {
66 | continue
67 | }
68 | callbacks.push(...(state.bindings.get(sequenceCode) || []))
69 | }
70 | return callbacks
71 | }
72 |
73 | export function handleEvent(state: State, event: KeyboardEvent): [State, Callback[]] {
74 | state = addEventToHistory(state, event)
75 | const fns = getMatchingCallbacks(state)
76 | for (const fn of fns) fn(event)
77 | return [state, fns]
78 | }
79 |
80 | export function updateHistorySize(state: State): State {
81 | state.historySize = 0
82 | for (const code of state.bindings.keys()) {
83 | state.historySize = Math.max(state.historySize, getSequenceSize(code))
84 | }
85 | return state
86 | }
87 |
--------------------------------------------------------------------------------
/src/test-utils.ts:
--------------------------------------------------------------------------------
1 | import {normalizeKey} from './key'
2 | import {encodeSequence} from './sequence'
3 | import {Callback, EncodedSequence, Key, Sequence} from './types'
4 |
5 | export function encode(...keys: Key[]) {
6 | return encodeSequence(keys.map(normalizeKey))
7 | }
8 |
9 | export function binding(seq: Sequence, ...fns: Callback[]) {
10 | return [encode(...seq), new Set(fns)] as [EncodedSequence, Set]
11 | }
12 |
13 | export function bindings(...items: Array<[Sequence, ...Callback[]]>) {
14 | return new Map(items.map((x) => binding(...x)))
15 | }
16 |
17 | export function fnMocks(...names: Name[]) {
18 | const fns = new Map()
19 | const callsCounts = new Map()
20 | for (const name of names) {
21 | fns.set(name, jest.fn())
22 | callsCounts.set(name, 0)
23 | }
24 | return {
25 | get(name: Name) {
26 | return fns.get(name)
27 | },
28 | call(...names: Name[]) {
29 | for (const name of names) {
30 | callsCounts.set(name, callsCounts.get(name) + 1)
31 | }
32 | return this
33 | },
34 | checkCalls() {
35 | for (const [name, fn] of fns) {
36 | const callsCount = callsCounts.get(name)
37 | try {
38 | expect(fn).toBeCalledTimes(callsCount)
39 | } catch {
40 | throw `Expected function '${name}' to be called ${callsCount} times, but it was called ${fn.mock.calls} times!`
41 | }
42 | }
43 | },
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | import {tuple} from 'just-types'
2 |
3 | type Modifiers = ['ctrl', 'alt', 'meta', 'shift']
4 | export type Modifier = Modifiers[number]
5 | export type AliasCharacter = 'space' | 'plus' | 'up' | 'down' | 'left' | 'right' | 'esc'
6 |
7 | export type Key = tuple.Join, '+'>
8 | export type NormalizedKey = tuple.SubArray> | [...tuple.SubArray>, C]
9 | export type EncodedKey = number
10 |
11 | export type Sequence = Key[]
12 | export type NormalizedSequence = NormalizedKey[]
13 | export type EncodedSequence = number
14 |
15 | export type KeyboardEventType = 'keydown' | 'keyup'
16 | export type Callback = (event?: KeyboardEvent) => any
17 | export type KeyboardEventListener = (event: KeyboardEvent) => any
18 | export type State = {
19 | history: EncodedKey[]
20 | historySize: number
21 | disabledSequenceCodes: Set
22 | bindings: Map>
23 | }
24 |
25 | export type Binding = [Key, Callback] | [Key, Key, Callback] | [Key, Key, Key, Callback] | [Key, Key, Key, Key, Callback]
26 | export interface HandlerInterface {
27 | add(...args: Binding): this
28 | remove(...args: Binding): this
29 | enable(...keys: Sequence): this
30 | disable(...keys: Sequence): this
31 | handle(event: KeyboardEvent): boolean
32 | }
33 |
34 | export type Character =
35 | | '_'
36 | | '0'
37 | | '1'
38 | | '2'
39 | | '3'
40 | | '4'
41 | | '5'
42 | | '6'
43 | | '7'
44 | | '8'
45 | | '9'
46 | | 'a'
47 | | 'b'
48 | | 'c'
49 | | 'd'
50 | | 'e'
51 | | 'f'
52 | | 'g'
53 | | 'h'
54 | | 'i'
55 | | 'j'
56 | | 'k'
57 | | 'l'
58 | | 'm'
59 | | 'n'
60 | | 'o'
61 | | 'p'
62 | | 'q'
63 | | 'r'
64 | | 's'
65 | | 't'
66 | | 'u'
67 | | 'v'
68 | | 'w'
69 | | 'x'
70 | | 'y'
71 | | 'z'
72 | | ' '
73 | | '`'
74 | | "'"
75 | | '"'
76 | | '~'
77 | | '!'
78 | | '@'
79 | | '#'
80 | | '$'
81 | | '%'
82 | | '^'
83 | | '&'
84 | | '*'
85 | | '('
86 | | ')'
87 | | '.'
88 | | '-'
89 | | '+'
90 | | '='
91 | | '['
92 | | ']'
93 | | '{'
94 | | '}'
95 | | '<'
96 | | '>'
97 | | ','
98 | | '/'
99 | | '?'
100 | | ';'
101 | | ':'
102 | | '\\'
103 | | '|'
104 | | 'capslock'
105 | | 'numlock'
106 | | 'enter'
107 | | 'tab'
108 | | 'arrowdown'
109 | | 'arrowleft'
110 | | 'arrowright'
111 | | 'arrowup'
112 | | 'end'
113 | | 'home'
114 | | 'pagedown'
115 | | 'pageup'
116 | | 'backspace'
117 | | 'delete'
118 | | 'insert'
119 | | 'escape'
120 | | 'f1'
121 | | 'f2'
122 | | 'f3'
123 | | 'f4'
124 | | 'f5'
125 | | 'f6'
126 | | 'f7'
127 | | 'f8'
128 | | 'f9'
129 | | 'f10'
130 | | 'f11'
131 | | 'f12'
132 | | 'f13'
133 | | 'f14'
134 | | 'f15'
135 | | 'f16'
136 | | 'f17'
137 | | 'f18'
138 | | 'f19'
139 | | 'f20'
140 | | 'f21'
141 | | 'f22'
142 | | 'f23'
143 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["src"],
3 | "compilerOptions": {
4 | "module": "ESNext",
5 | "lib": ["dom", "esnext"],
6 | "importHelpers": true,
7 | "declaration": true,
8 | "sourceMap": true,
9 | "rootDir": "./src",
10 | "strict": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "noUnusedLocals": true,
14 | "noUnusedParameters": true,
15 | "moduleResolution": "node",
16 | "jsx": "react",
17 | "esModuleInterop": true,
18 | "skipLibCheck": true,
19 | "forceConsistentCasingInFileNames": true,
20 | "noEmit": true,
21 | "downlevelIteration": true
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup'
2 |
3 | export default defineConfig({
4 | entry: ['src/index.ts'],
5 | format: ['cjs', 'esm'],
6 | dts: {
7 | resolve: true,
8 | entry: 'src/index.ts'
9 | },
10 | clean: true,
11 | minify: true,
12 | sourcemap: true,
13 | target: 'es2018',
14 | outDir: 'dist',
15 | noExternal: ['just-types']
16 | })
17 |
--------------------------------------------------------------------------------