├── .gitignore
├── LICENSE
├── README.md
├── config.ini.sample
├── hijack.js
├── imes
└── remapper
├── package-lock.json
├── package.json
├── remapper
├── engine.js
├── keymap.js
├── main.js
├── manifest.json
└── preamble.js
└── wscript
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | /build/
3 | /config.ini
4 | /imes/*
5 | !/imes/remapper
6 | .lock*
7 | /node_modules/
8 | /waf
9 | /waf-*
10 | .waf*
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Marica Odagaki
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # chromeos-key-remapper
2 |
3 | This repo contains:
4 |
5 | 1. An unpublished Chrome OS IME that lets you use emacs-like cursor movement
6 | keys with a US English keyboard. `C-a` and `C-k`, to name a few.
7 | 2. Tooling to build a custom IME that combines the remapper engine and other 3rd party IMEs.
8 |
9 | ## Limitations
10 |
11 | - All the combined IMEs share the same JavaScript scope. Name collision
12 | can happen.
13 | - The options page of the custom IME can only display the options page of a
14 | single IME.
15 | - Keys can be only remapped to other key combinations. i.e. can't do things
16 | that the OS already supports through exiting key combos.
17 | - Only a single key combo can be mapped: no support for sequence of keys.
18 |
19 | ## Prerequisites / assumptions
20 |
21 | For the premade IME:
22 |
23 | - You don't want to remap when you're in crosh window
24 |
25 | Additionally, for the make-your-own route:
26 |
27 | - python (I use 3.x; 2.x _probably_ works)
28 | - [`waf` command](https://waf.io/book/#_download_and_installation)
29 | - `waf*` is gitignored in this repo; I have it downloaded to the root of my local clone
30 | - [`jscodeshift` command](https://github.com/facebook/jscodeshift)
31 | - `npm install` in this repo and add `./node_module/.bin` to `$PATH` when invoking `waf`
32 | - or: `npm install -g jscodeshift`
33 |
34 | ## How to install
35 |
36 | First, download this repo as a zip file and unpack it or clone the repo.
37 | Chrome OS needs to have access to the file system where your local copy resides.
38 |
39 | Go to chrome://extensions and enable developer mode.
40 |
41 | ### Using the premade IME
42 |
43 | In chrome://extensions, click the "Load unpacked extension..." button
44 | and pick the `remapper` directory in your local copy of the repo.
45 |
46 | Open Settings, then search for "manage input methods." Click the highlighted row
47 | with that label. There should be a row named "US x emacs"; check to enable it.
48 |
49 | Now, pressing Ctrl-Shift-Space will cycle through all the
50 | IMEs that are enabled. Hit Ctrl-Space to switch back and forth
51 | between the previously selected IME.
52 |
53 | There's an indicator next to the notification indicator that shows the active
54 | IME: make sure you've activated the IME you just installed and try out
55 | a few bindings like `C-f`, `C-b` in a text field.
56 |
57 | See [`remapper/keymap.js`](./remapper/keymap.js) for the keybindings.
58 | If you want different bindings, edit this file and reload the extension.
59 |
60 | ### Making your own with a different language and/or layout
61 |
62 | You need to create a `config.ini` file. `config.ini.sample` is a good
63 | starting point:
64 |
65 | ```sh
66 | cp config.ini.sample config.ini
67 | ```
68 |
69 | The config file can contain multiple sections. Each section, when
70 | built, will result in a directory under `./build` that contains an
71 | IME extension. An IME extension can potentially hold multiple
72 | IMEs; however, this tooling only supports a single IME per extension.
73 |
74 | Here's what a section looks like:
75 |
76 | ```ini
77 | [us_emacs]
78 | name = EN x emacs
79 | description = US keyboard with emacs-like cursor movement
80 | language = en-US
81 | layout = us
82 | fallback_imes =
83 | options_page =
84 | ```
85 |
86 | `[us_emacs]` is the section name, which will become the name of the directory.
87 |
88 | `name` and `description` will become the name and description of both the extension
89 | and the IME you see in Settings.
90 |
91 | `language` and `layout` dictate which language and layout the IME will be for.
92 | Change these to make an IME for your preferred language and layout. I'm not sure
93 | what values are accepted here. The [extra keyboards repo][extra-keyboard] may
94 | be a good resource.
95 |
96 | `fallback_imes` and `options_page` are irrelevant to what we're doing now; we'll
97 | come back to it later.
98 |
99 | To build an IME out of this config file, run `waf`:
100 |
101 | ```sh
102 | python waf configure build
103 | ```
104 |
105 | This should create a directory `./build/us_emacs/`, which you can install
106 | like the premade one above.
107 |
108 | ### Making your own by combining other IMEs
109 |
110 | The basic steps are the same as the above: create `config.ini` and run `waf`.
111 |
112 | This time, we actually make use of `fallback_imes` and `options_page`.
113 |
114 | `fallback_imes` is a comma-separated list of directory names you put
115 | in `./imes`. Said directories must contain an IME extension. All
116 | files in the directory will be copied to
117 | `build/[config_section_name]/[fallback_ime_name]/`, with `.js` files
118 | getting special treatment to make all this work.
119 |
120 | `options_page` should be the path to the options page to use, relative
121 | to the built extension's root: `[fallback_ime_name]/options.html`, for example.
122 |
123 | How you place an IME extension under `./imes` is up to you. You could
124 | clone a repo there, or symlink to a directory outside the repo.
125 |
126 | Let's see an example of how all this fits together.
127 |
128 | I want to use my emacs keybindings on top of [Chrome SKK][skk], a Japanese
129 | IME, so here's what I do:
130 |
131 | ```
132 | chrome-skk/
133 | chrome-key-remapper/
134 | config.ini
135 | imes/
136 | skk -> ../../chrome-skk/extension
137 | remapper/
138 | ..
139 | ```
140 |
141 | With a config like:
142 |
143 | ```
144 | [skk_remapped]
145 | name = SKK x emacs
146 | description = SKK with emacs-like cursor movement
147 | language = ja
148 | layout = us
149 | fallback_imes = skk
150 | options_page = skk/options.html
151 | ```
152 |
153 | When I invoke `python waf configure build`, an IME extension gets built in `./build/`:
154 |
155 | ```
156 | chrome-key-remapper/
157 | build/
158 | skk_remapped/
159 | manifest.json
160 | remapper/
161 | main.js
162 | ..
163 | skk/
164 | main.js
165 | ..
166 | ```
167 |
168 | With this hybrid IME enabled and active, any key event not handled by
169 | the remapper will get passed onto SKK, enabling me to input Japanese
170 | text while enjoying the familiar emacs-like cursor movement keys.
171 |
172 | [extra-keyboard]: https://github.com/google/extra-keyboards-for-chrome-os
173 | [skk]: https://github.com/jmuk/chrome-skk
174 |
--------------------------------------------------------------------------------
/config.ini.sample:
--------------------------------------------------------------------------------
1 | [us_emacs]
2 | name = US x emacs
3 | description = US keyboard with emacs-like cursor movement
4 | language = en-US
5 | layout = us
6 | fallback_imes =
7 | options_page =
8 |
--------------------------------------------------------------------------------
/hijack.js:
--------------------------------------------------------------------------------
1 | /* Rewrite calls to chrome.input.ime.onX.addListener as
2 | Remapper.hijack.onX.addListener.
3 | */
4 |
5 | var fs = require('fs');
6 | const jscodeshift = require('jscodeshift');
7 |
8 | function baseFilter() {
9 | return {
10 | callee: {
11 | property: {name: "addListener"},
12 | object: {
13 | object: {
14 | property: {name: "ime"},
15 | object: {
16 | property: {name: "input"},
17 | object: {
18 | name: "chrome"
19 | }
20 | }
21 | }
22 | }
23 | }
24 | };
25 | }
26 |
27 | // filter for calls like `ime.onKeyData`
28 | function propertyMemberFilter() {
29 | const filter = baseFilter();
30 | filter.callee.object.computed = false; // ignore dynamic member lookup like `ime[eventName]`
31 | filter.callee.object.property = {type: "Identifier"};
32 | return filter;
33 | }
34 |
35 | function propertyMemberEvent(path) {
36 | return path.node.callee.object.property.name;
37 | }
38 |
39 | // filter for calls like `ime["onKeyData"]`
40 | function literalMemberFilter() {
41 | const filter = baseFilter();
42 | filter.callee.object.computed = true;
43 | filter.callee.object.property = {type: "Literal"};
44 | return filter;
45 | }
46 |
47 | function literalMemberEvent(path) {
48 | return path.node.callee.object.property.value;
49 | }
50 |
51 | function rewrite(j, getEventName) {
52 | return function(path) {
53 | {
54 | j(path).replaceWith(
55 | j.callExpression(j.memberExpression(
56 | j.memberExpression(
57 | j.memberExpression(
58 | j.identifier("Remapper"),
59 | j.identifier("hijack"), // onX
60 | false),
61 | j.identifier(getEventName(path)), // onX
62 | false),
63 | j.identifier(path.node.callee.property.name), // addListener
64 | false),
65 | path.node.arguments)
66 | );
67 | }
68 | };
69 | }
70 |
71 | function transformer(file, api) {
72 | const j = api.jscodeshift;
73 | const root = j(file.source);
74 | root.find(j.CallExpression, propertyMemberFilter())
75 | .forEach(rewrite(j, propertyMemberEvent));
76 | root.find(j.CallExpression, literalMemberFilter())
77 | .forEach(rewrite(j, literalMemberEvent))
78 | return root.toSource();
79 | }
80 |
81 | if (process.argv.length < 4) {
82 | console.error("you should be invoking waf instead of this script, but if you really need to know:");
83 | console.error('usage: node hijack.js input_path output_path');
84 | process.exit(1);
85 | }
86 |
87 | // the jscodeshift command rewrites files in place, and waf doesn't
88 | // like it when the input and output are the same file. so this is a
89 | // simple wrapper around the jscodeshift transformer function that
90 | // reads JS code from the specified input path, transforms it, and
91 | // writes to the specified output path.
92 | fs.readFile(process.argv[2], {encoding: 'utf8'}, function(err, source) {
93 | if (err) {
94 | console.error(err);
95 | process.exit(1);
96 | }
97 | var result = transformer({source: source}, {jscodeshift: jscodeshift});
98 | fs.writeFile(process.argv[3], result, function(err) {
99 | if (err) {
100 | console.error(err);
101 | process.exit(1);
102 | }
103 | });
104 | })
105 |
--------------------------------------------------------------------------------
/imes/remapper:
--------------------------------------------------------------------------------
1 | ../remapper
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chromeos-key-remapper",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@ampproject/remapping": {
8 | "version": "2.2.0",
9 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
10 | "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
11 | "requires": {
12 | "@jridgewell/gen-mapping": "^0.1.0",
13 | "@jridgewell/trace-mapping": "^0.3.9"
14 | }
15 | },
16 | "@babel/code-frame": {
17 | "version": "7.21.4",
18 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
19 | "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
20 | "requires": {
21 | "@babel/highlight": "^7.18.6"
22 | }
23 | },
24 | "@babel/compat-data": {
25 | "version": "7.21.4",
26 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz",
27 | "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g=="
28 | },
29 | "@babel/core": {
30 | "version": "7.21.4",
31 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz",
32 | "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==",
33 | "requires": {
34 | "@ampproject/remapping": "^2.2.0",
35 | "@babel/code-frame": "^7.21.4",
36 | "@babel/generator": "^7.21.4",
37 | "@babel/helper-compilation-targets": "^7.21.4",
38 | "@babel/helper-module-transforms": "^7.21.2",
39 | "@babel/helpers": "^7.21.0",
40 | "@babel/parser": "^7.21.4",
41 | "@babel/template": "^7.20.7",
42 | "@babel/traverse": "^7.21.4",
43 | "@babel/types": "^7.21.4",
44 | "convert-source-map": "^1.7.0",
45 | "debug": "^4.1.0",
46 | "gensync": "^1.0.0-beta.2",
47 | "json5": "^2.2.2",
48 | "semver": "^6.3.0"
49 | }
50 | },
51 | "@babel/generator": {
52 | "version": "7.21.4",
53 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz",
54 | "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==",
55 | "requires": {
56 | "@babel/types": "^7.21.4",
57 | "@jridgewell/gen-mapping": "^0.3.2",
58 | "@jridgewell/trace-mapping": "^0.3.17",
59 | "jsesc": "^2.5.1"
60 | },
61 | "dependencies": {
62 | "@jridgewell/gen-mapping": {
63 | "version": "0.3.2",
64 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
65 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
66 | "requires": {
67 | "@jridgewell/set-array": "^1.0.1",
68 | "@jridgewell/sourcemap-codec": "^1.4.10",
69 | "@jridgewell/trace-mapping": "^0.3.9"
70 | }
71 | }
72 | }
73 | },
74 | "@babel/helper-annotate-as-pure": {
75 | "version": "7.18.6",
76 | "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
77 | "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
78 | "requires": {
79 | "@babel/types": "^7.18.6"
80 | }
81 | },
82 | "@babel/helper-compilation-targets": {
83 | "version": "7.21.4",
84 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz",
85 | "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==",
86 | "requires": {
87 | "@babel/compat-data": "^7.21.4",
88 | "@babel/helper-validator-option": "^7.21.0",
89 | "browserslist": "^4.21.3",
90 | "lru-cache": "^5.1.1",
91 | "semver": "^6.3.0"
92 | }
93 | },
94 | "@babel/helper-create-class-features-plugin": {
95 | "version": "7.21.4",
96 | "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz",
97 | "integrity": "sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==",
98 | "requires": {
99 | "@babel/helper-annotate-as-pure": "^7.18.6",
100 | "@babel/helper-environment-visitor": "^7.18.9",
101 | "@babel/helper-function-name": "^7.21.0",
102 | "@babel/helper-member-expression-to-functions": "^7.21.0",
103 | "@babel/helper-optimise-call-expression": "^7.18.6",
104 | "@babel/helper-replace-supers": "^7.20.7",
105 | "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
106 | "@babel/helper-split-export-declaration": "^7.18.6"
107 | }
108 | },
109 | "@babel/helper-environment-visitor": {
110 | "version": "7.18.9",
111 | "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
112 | "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg=="
113 | },
114 | "@babel/helper-function-name": {
115 | "version": "7.21.0",
116 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
117 | "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
118 | "requires": {
119 | "@babel/template": "^7.20.7",
120 | "@babel/types": "^7.21.0"
121 | }
122 | },
123 | "@babel/helper-hoist-variables": {
124 | "version": "7.18.6",
125 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
126 | "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
127 | "requires": {
128 | "@babel/types": "^7.18.6"
129 | }
130 | },
131 | "@babel/helper-member-expression-to-functions": {
132 | "version": "7.21.0",
133 | "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz",
134 | "integrity": "sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==",
135 | "requires": {
136 | "@babel/types": "^7.21.0"
137 | }
138 | },
139 | "@babel/helper-module-imports": {
140 | "version": "7.21.4",
141 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
142 | "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
143 | "requires": {
144 | "@babel/types": "^7.21.4"
145 | }
146 | },
147 | "@babel/helper-module-transforms": {
148 | "version": "7.21.2",
149 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
150 | "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
151 | "requires": {
152 | "@babel/helper-environment-visitor": "^7.18.9",
153 | "@babel/helper-module-imports": "^7.18.6",
154 | "@babel/helper-simple-access": "^7.20.2",
155 | "@babel/helper-split-export-declaration": "^7.18.6",
156 | "@babel/helper-validator-identifier": "^7.19.1",
157 | "@babel/template": "^7.20.7",
158 | "@babel/traverse": "^7.21.2",
159 | "@babel/types": "^7.21.2"
160 | }
161 | },
162 | "@babel/helper-optimise-call-expression": {
163 | "version": "7.18.6",
164 | "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz",
165 | "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==",
166 | "requires": {
167 | "@babel/types": "^7.18.6"
168 | }
169 | },
170 | "@babel/helper-plugin-utils": {
171 | "version": "7.20.2",
172 | "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
173 | "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ=="
174 | },
175 | "@babel/helper-replace-supers": {
176 | "version": "7.20.7",
177 | "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz",
178 | "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==",
179 | "requires": {
180 | "@babel/helper-environment-visitor": "^7.18.9",
181 | "@babel/helper-member-expression-to-functions": "^7.20.7",
182 | "@babel/helper-optimise-call-expression": "^7.18.6",
183 | "@babel/template": "^7.20.7",
184 | "@babel/traverse": "^7.20.7",
185 | "@babel/types": "^7.20.7"
186 | }
187 | },
188 | "@babel/helper-simple-access": {
189 | "version": "7.20.2",
190 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
191 | "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
192 | "requires": {
193 | "@babel/types": "^7.20.2"
194 | }
195 | },
196 | "@babel/helper-skip-transparent-expression-wrappers": {
197 | "version": "7.20.0",
198 | "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz",
199 | "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==",
200 | "requires": {
201 | "@babel/types": "^7.20.0"
202 | }
203 | },
204 | "@babel/helper-split-export-declaration": {
205 | "version": "7.18.6",
206 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
207 | "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
208 | "requires": {
209 | "@babel/types": "^7.18.6"
210 | }
211 | },
212 | "@babel/helper-string-parser": {
213 | "version": "7.19.4",
214 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
215 | "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw=="
216 | },
217 | "@babel/helper-validator-identifier": {
218 | "version": "7.19.1",
219 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
220 | "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w=="
221 | },
222 | "@babel/helper-validator-option": {
223 | "version": "7.21.0",
224 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz",
225 | "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ=="
226 | },
227 | "@babel/helpers": {
228 | "version": "7.21.0",
229 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz",
230 | "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==",
231 | "requires": {
232 | "@babel/template": "^7.20.7",
233 | "@babel/traverse": "^7.21.0",
234 | "@babel/types": "^7.21.0"
235 | }
236 | },
237 | "@babel/highlight": {
238 | "version": "7.18.6",
239 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
240 | "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
241 | "requires": {
242 | "@babel/helper-validator-identifier": "^7.18.6",
243 | "chalk": "^2.0.0",
244 | "js-tokens": "^4.0.0"
245 | },
246 | "dependencies": {
247 | "chalk": {
248 | "version": "2.4.2",
249 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
250 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
251 | "requires": {
252 | "ansi-styles": "^3.2.1",
253 | "escape-string-regexp": "^1.0.5",
254 | "supports-color": "^5.3.0"
255 | }
256 | }
257 | }
258 | },
259 | "@babel/parser": {
260 | "version": "7.21.4",
261 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
262 | "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw=="
263 | },
264 | "@babel/plugin-proposal-class-properties": {
265 | "version": "7.18.6",
266 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz",
267 | "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==",
268 | "requires": {
269 | "@babel/helper-create-class-features-plugin": "^7.18.6",
270 | "@babel/helper-plugin-utils": "^7.18.6"
271 | }
272 | },
273 | "@babel/plugin-proposal-nullish-coalescing-operator": {
274 | "version": "7.18.6",
275 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz",
276 | "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==",
277 | "requires": {
278 | "@babel/helper-plugin-utils": "^7.18.6",
279 | "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
280 | }
281 | },
282 | "@babel/plugin-proposal-optional-chaining": {
283 | "version": "7.21.0",
284 | "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz",
285 | "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==",
286 | "requires": {
287 | "@babel/helper-plugin-utils": "^7.20.2",
288 | "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
289 | "@babel/plugin-syntax-optional-chaining": "^7.8.3"
290 | }
291 | },
292 | "@babel/plugin-syntax-flow": {
293 | "version": "7.21.4",
294 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.21.4.tgz",
295 | "integrity": "sha512-l9xd3N+XG4fZRxEP3vXdK6RW7vN1Uf5dxzRC/09wV86wqZ/YYQooBIGNsiRdfNR3/q2/5pPzV4B54J/9ctX5jw==",
296 | "requires": {
297 | "@babel/helper-plugin-utils": "^7.20.2"
298 | }
299 | },
300 | "@babel/plugin-syntax-jsx": {
301 | "version": "7.21.4",
302 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz",
303 | "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==",
304 | "requires": {
305 | "@babel/helper-plugin-utils": "^7.20.2"
306 | }
307 | },
308 | "@babel/plugin-syntax-nullish-coalescing-operator": {
309 | "version": "7.8.3",
310 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
311 | "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
312 | "requires": {
313 | "@babel/helper-plugin-utils": "^7.8.0"
314 | }
315 | },
316 | "@babel/plugin-syntax-optional-chaining": {
317 | "version": "7.8.3",
318 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
319 | "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
320 | "requires": {
321 | "@babel/helper-plugin-utils": "^7.8.0"
322 | }
323 | },
324 | "@babel/plugin-syntax-typescript": {
325 | "version": "7.21.4",
326 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz",
327 | "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==",
328 | "requires": {
329 | "@babel/helper-plugin-utils": "^7.20.2"
330 | }
331 | },
332 | "@babel/plugin-transform-flow-strip-types": {
333 | "version": "7.21.0",
334 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz",
335 | "integrity": "sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w==",
336 | "requires": {
337 | "@babel/helper-plugin-utils": "^7.20.2",
338 | "@babel/plugin-syntax-flow": "^7.18.6"
339 | }
340 | },
341 | "@babel/plugin-transform-modules-commonjs": {
342 | "version": "7.21.2",
343 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz",
344 | "integrity": "sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==",
345 | "requires": {
346 | "@babel/helper-module-transforms": "^7.21.2",
347 | "@babel/helper-plugin-utils": "^7.20.2",
348 | "@babel/helper-simple-access": "^7.20.2"
349 | }
350 | },
351 | "@babel/plugin-transform-typescript": {
352 | "version": "7.21.3",
353 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz",
354 | "integrity": "sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==",
355 | "requires": {
356 | "@babel/helper-annotate-as-pure": "^7.18.6",
357 | "@babel/helper-create-class-features-plugin": "^7.21.0",
358 | "@babel/helper-plugin-utils": "^7.20.2",
359 | "@babel/plugin-syntax-typescript": "^7.20.0"
360 | }
361 | },
362 | "@babel/preset-flow": {
363 | "version": "7.21.4",
364 | "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.21.4.tgz",
365 | "integrity": "sha512-F24cSq4DIBmhq4OzK3dE63NHagb27OPE3eWR+HLekt4Z3Y5MzIIUGF3LlLgV0gN8vzbDViSY7HnrReNVCJXTeA==",
366 | "requires": {
367 | "@babel/helper-plugin-utils": "^7.20.2",
368 | "@babel/helper-validator-option": "^7.21.0",
369 | "@babel/plugin-transform-flow-strip-types": "^7.21.0"
370 | }
371 | },
372 | "@babel/preset-typescript": {
373 | "version": "7.21.4",
374 | "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.4.tgz",
375 | "integrity": "sha512-sMLNWY37TCdRH/bJ6ZeeOH1nPuanED7Ai9Y/vH31IPqalioJ6ZNFUWONsakhv4r4n+I6gm5lmoE0olkgib/j/A==",
376 | "requires": {
377 | "@babel/helper-plugin-utils": "^7.20.2",
378 | "@babel/helper-validator-option": "^7.21.0",
379 | "@babel/plugin-syntax-jsx": "^7.21.4",
380 | "@babel/plugin-transform-modules-commonjs": "^7.21.2",
381 | "@babel/plugin-transform-typescript": "^7.21.3"
382 | }
383 | },
384 | "@babel/register": {
385 | "version": "7.21.0",
386 | "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.21.0.tgz",
387 | "integrity": "sha512-9nKsPmYDi5DidAqJaQooxIhsLJiNMkGr8ypQ8Uic7cIox7UCDsM7HuUGxdGT7mSDTYbqzIdsOWzfBton/YJrMw==",
388 | "requires": {
389 | "clone-deep": "^4.0.1",
390 | "find-cache-dir": "^2.0.0",
391 | "make-dir": "^2.1.0",
392 | "pirates": "^4.0.5",
393 | "source-map-support": "^0.5.16"
394 | }
395 | },
396 | "@babel/template": {
397 | "version": "7.20.7",
398 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
399 | "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
400 | "requires": {
401 | "@babel/code-frame": "^7.18.6",
402 | "@babel/parser": "^7.20.7",
403 | "@babel/types": "^7.20.7"
404 | }
405 | },
406 | "@babel/traverse": {
407 | "version": "7.21.4",
408 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz",
409 | "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==",
410 | "requires": {
411 | "@babel/code-frame": "^7.21.4",
412 | "@babel/generator": "^7.21.4",
413 | "@babel/helper-environment-visitor": "^7.18.9",
414 | "@babel/helper-function-name": "^7.21.0",
415 | "@babel/helper-hoist-variables": "^7.18.6",
416 | "@babel/helper-split-export-declaration": "^7.18.6",
417 | "@babel/parser": "^7.21.4",
418 | "@babel/types": "^7.21.4",
419 | "debug": "^4.1.0",
420 | "globals": "^11.1.0"
421 | }
422 | },
423 | "@babel/types": {
424 | "version": "7.21.4",
425 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz",
426 | "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==",
427 | "requires": {
428 | "@babel/helper-string-parser": "^7.19.4",
429 | "@babel/helper-validator-identifier": "^7.19.1",
430 | "to-fast-properties": "^2.0.0"
431 | }
432 | },
433 | "@jridgewell/gen-mapping": {
434 | "version": "0.1.1",
435 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
436 | "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
437 | "requires": {
438 | "@jridgewell/set-array": "^1.0.0",
439 | "@jridgewell/sourcemap-codec": "^1.4.10"
440 | }
441 | },
442 | "@jridgewell/resolve-uri": {
443 | "version": "3.1.0",
444 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
445 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w=="
446 | },
447 | "@jridgewell/set-array": {
448 | "version": "1.1.2",
449 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
450 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw=="
451 | },
452 | "@jridgewell/sourcemap-codec": {
453 | "version": "1.4.14",
454 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
455 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
456 | },
457 | "@jridgewell/trace-mapping": {
458 | "version": "0.3.17",
459 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
460 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
461 | "requires": {
462 | "@jridgewell/resolve-uri": "3.1.0",
463 | "@jridgewell/sourcemap-codec": "1.4.14"
464 | }
465 | },
466 | "ansi-styles": {
467 | "version": "3.2.1",
468 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
469 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
470 | "requires": {
471 | "color-convert": "^1.9.0"
472 | }
473 | },
474 | "ast-types": {
475 | "version": "0.15.2",
476 | "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz",
477 | "integrity": "sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==",
478 | "requires": {
479 | "tslib": "^2.0.1"
480 | }
481 | },
482 | "babel-core": {
483 | "version": "7.0.0-bridge.0",
484 | "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
485 | "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg=="
486 | },
487 | "balanced-match": {
488 | "version": "1.0.2",
489 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
490 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
491 | },
492 | "brace-expansion": {
493 | "version": "1.1.11",
494 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
495 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
496 | "requires": {
497 | "balanced-match": "^1.0.0",
498 | "concat-map": "0.0.1"
499 | }
500 | },
501 | "braces": {
502 | "version": "3.0.2",
503 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
504 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
505 | "requires": {
506 | "fill-range": "^7.0.1"
507 | }
508 | },
509 | "browserslist": {
510 | "version": "4.21.5",
511 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
512 | "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
513 | "requires": {
514 | "caniuse-lite": "^1.0.30001449",
515 | "electron-to-chromium": "^1.4.284",
516 | "node-releases": "^2.0.8",
517 | "update-browserslist-db": "^1.0.10"
518 | }
519 | },
520 | "buffer-from": {
521 | "version": "1.1.2",
522 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
523 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
524 | },
525 | "caniuse-lite": {
526 | "version": "1.0.30001474",
527 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz",
528 | "integrity": "sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q=="
529 | },
530 | "chalk": {
531 | "version": "4.1.2",
532 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
533 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
534 | "requires": {
535 | "ansi-styles": "^4.1.0",
536 | "supports-color": "^7.1.0"
537 | },
538 | "dependencies": {
539 | "ansi-styles": {
540 | "version": "4.3.0",
541 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
542 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
543 | "requires": {
544 | "color-convert": "^2.0.1"
545 | }
546 | },
547 | "color-convert": {
548 | "version": "2.0.1",
549 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
550 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
551 | "requires": {
552 | "color-name": "~1.1.4"
553 | }
554 | },
555 | "color-name": {
556 | "version": "1.1.4",
557 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
558 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
559 | },
560 | "has-flag": {
561 | "version": "4.0.0",
562 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
563 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
564 | },
565 | "supports-color": {
566 | "version": "7.2.0",
567 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
568 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
569 | "requires": {
570 | "has-flag": "^4.0.0"
571 | }
572 | }
573 | }
574 | },
575 | "clone-deep": {
576 | "version": "4.0.1",
577 | "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
578 | "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
579 | "requires": {
580 | "is-plain-object": "^2.0.4",
581 | "kind-of": "^6.0.2",
582 | "shallow-clone": "^3.0.0"
583 | }
584 | },
585 | "color-convert": {
586 | "version": "1.9.3",
587 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
588 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
589 | "requires": {
590 | "color-name": "1.1.3"
591 | }
592 | },
593 | "color-name": {
594 | "version": "1.1.3",
595 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
596 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
597 | },
598 | "commondir": {
599 | "version": "1.0.1",
600 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
601 | "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="
602 | },
603 | "concat-map": {
604 | "version": "0.0.1",
605 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
606 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
607 | },
608 | "convert-source-map": {
609 | "version": "1.9.0",
610 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
611 | "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
612 | },
613 | "debug": {
614 | "version": "4.3.4",
615 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
616 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
617 | "requires": {
618 | "ms": "2.1.2"
619 | }
620 | },
621 | "electron-to-chromium": {
622 | "version": "1.4.350",
623 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.350.tgz",
624 | "integrity": "sha512-XnXcWpVnOfHZ4C3NPiL+SubeoGV8zc/pg8GEubRtc1dPA/9jKS2vsOPmtClJHhWxUb2RSGC1OBLCbgNUJMtZPw=="
625 | },
626 | "escalade": {
627 | "version": "3.1.1",
628 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
629 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
630 | },
631 | "escape-string-regexp": {
632 | "version": "1.0.5",
633 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
634 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
635 | },
636 | "esprima": {
637 | "version": "4.0.1",
638 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
639 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
640 | },
641 | "fill-range": {
642 | "version": "7.0.1",
643 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
644 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
645 | "requires": {
646 | "to-regex-range": "^5.0.1"
647 | }
648 | },
649 | "find-cache-dir": {
650 | "version": "2.1.0",
651 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
652 | "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
653 | "requires": {
654 | "commondir": "^1.0.1",
655 | "make-dir": "^2.0.0",
656 | "pkg-dir": "^3.0.0"
657 | }
658 | },
659 | "find-up": {
660 | "version": "3.0.0",
661 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
662 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
663 | "requires": {
664 | "locate-path": "^3.0.0"
665 | }
666 | },
667 | "flow-parser": {
668 | "version": "0.203.1",
669 | "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.203.1.tgz",
670 | "integrity": "sha512-Nw2M8MPP/Zb+yhvmPDEjzkCXLtgyWGKXZjAYOVftm+wIf3xd4FKa7nRI9v67rODs0WzxMbPc8IPs/7o/dyxo/Q=="
671 | },
672 | "fs.realpath": {
673 | "version": "1.0.0",
674 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
675 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
676 | },
677 | "gensync": {
678 | "version": "1.0.0-beta.2",
679 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
680 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
681 | },
682 | "glob": {
683 | "version": "7.2.3",
684 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
685 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
686 | "requires": {
687 | "fs.realpath": "^1.0.0",
688 | "inflight": "^1.0.4",
689 | "inherits": "2",
690 | "minimatch": "^3.1.1",
691 | "once": "^1.3.0",
692 | "path-is-absolute": "^1.0.0"
693 | }
694 | },
695 | "globals": {
696 | "version": "11.12.0",
697 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
698 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
699 | },
700 | "graceful-fs": {
701 | "version": "4.2.11",
702 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
703 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
704 | },
705 | "has-flag": {
706 | "version": "3.0.0",
707 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
708 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
709 | },
710 | "imurmurhash": {
711 | "version": "0.1.4",
712 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
713 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="
714 | },
715 | "inflight": {
716 | "version": "1.0.6",
717 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
718 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
719 | "requires": {
720 | "once": "^1.3.0",
721 | "wrappy": "1"
722 | }
723 | },
724 | "inherits": {
725 | "version": "2.0.4",
726 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
727 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
728 | },
729 | "is-number": {
730 | "version": "7.0.0",
731 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
732 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
733 | },
734 | "is-plain-object": {
735 | "version": "2.0.4",
736 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
737 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
738 | "requires": {
739 | "isobject": "^3.0.1"
740 | }
741 | },
742 | "isobject": {
743 | "version": "3.0.1",
744 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
745 | "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="
746 | },
747 | "js-tokens": {
748 | "version": "4.0.0",
749 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
750 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
751 | },
752 | "jscodeshift": {
753 | "version": "0.14.0",
754 | "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.14.0.tgz",
755 | "integrity": "sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==",
756 | "requires": {
757 | "@babel/core": "^7.13.16",
758 | "@babel/parser": "^7.13.16",
759 | "@babel/plugin-proposal-class-properties": "^7.13.0",
760 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8",
761 | "@babel/plugin-proposal-optional-chaining": "^7.13.12",
762 | "@babel/plugin-transform-modules-commonjs": "^7.13.8",
763 | "@babel/preset-flow": "^7.13.13",
764 | "@babel/preset-typescript": "^7.13.0",
765 | "@babel/register": "^7.13.16",
766 | "babel-core": "^7.0.0-bridge.0",
767 | "chalk": "^4.1.2",
768 | "flow-parser": "0.*",
769 | "graceful-fs": "^4.2.4",
770 | "micromatch": "^4.0.4",
771 | "neo-async": "^2.5.0",
772 | "node-dir": "^0.1.17",
773 | "recast": "^0.21.0",
774 | "temp": "^0.8.4",
775 | "write-file-atomic": "^2.3.0"
776 | }
777 | },
778 | "jsesc": {
779 | "version": "2.5.2",
780 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
781 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
782 | },
783 | "json5": {
784 | "version": "2.2.3",
785 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
786 | "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
787 | },
788 | "kind-of": {
789 | "version": "6.0.3",
790 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
791 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
792 | },
793 | "locate-path": {
794 | "version": "3.0.0",
795 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
796 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
797 | "requires": {
798 | "p-locate": "^3.0.0",
799 | "path-exists": "^3.0.0"
800 | }
801 | },
802 | "lru-cache": {
803 | "version": "5.1.1",
804 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
805 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
806 | "requires": {
807 | "yallist": "^3.0.2"
808 | }
809 | },
810 | "make-dir": {
811 | "version": "2.1.0",
812 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
813 | "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
814 | "requires": {
815 | "pify": "^4.0.1",
816 | "semver": "^5.6.0"
817 | },
818 | "dependencies": {
819 | "semver": {
820 | "version": "5.7.1",
821 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
822 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
823 | }
824 | }
825 | },
826 | "micromatch": {
827 | "version": "4.0.5",
828 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
829 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
830 | "requires": {
831 | "braces": "^3.0.2",
832 | "picomatch": "^2.3.1"
833 | }
834 | },
835 | "minimatch": {
836 | "version": "3.1.2",
837 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
838 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
839 | "requires": {
840 | "brace-expansion": "^1.1.7"
841 | }
842 | },
843 | "ms": {
844 | "version": "2.1.2",
845 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
846 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
847 | },
848 | "neo-async": {
849 | "version": "2.6.2",
850 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
851 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
852 | },
853 | "node-dir": {
854 | "version": "0.1.17",
855 | "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz",
856 | "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==",
857 | "requires": {
858 | "minimatch": "^3.0.2"
859 | }
860 | },
861 | "node-releases": {
862 | "version": "2.0.10",
863 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
864 | "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w=="
865 | },
866 | "once": {
867 | "version": "1.4.0",
868 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
869 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
870 | "requires": {
871 | "wrappy": "1"
872 | }
873 | },
874 | "p-limit": {
875 | "version": "2.3.0",
876 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
877 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
878 | "requires": {
879 | "p-try": "^2.0.0"
880 | }
881 | },
882 | "p-locate": {
883 | "version": "3.0.0",
884 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
885 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
886 | "requires": {
887 | "p-limit": "^2.0.0"
888 | }
889 | },
890 | "p-try": {
891 | "version": "2.2.0",
892 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
893 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
894 | },
895 | "path-exists": {
896 | "version": "3.0.0",
897 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
898 | "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="
899 | },
900 | "path-is-absolute": {
901 | "version": "1.0.1",
902 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
903 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
904 | },
905 | "picocolors": {
906 | "version": "1.0.0",
907 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
908 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
909 | },
910 | "picomatch": {
911 | "version": "2.3.1",
912 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
913 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
914 | },
915 | "pify": {
916 | "version": "4.0.1",
917 | "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
918 | "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
919 | },
920 | "pirates": {
921 | "version": "4.0.5",
922 | "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
923 | "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ=="
924 | },
925 | "pkg-dir": {
926 | "version": "3.0.0",
927 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
928 | "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
929 | "requires": {
930 | "find-up": "^3.0.0"
931 | }
932 | },
933 | "recast": {
934 | "version": "0.21.5",
935 | "resolved": "https://registry.npmjs.org/recast/-/recast-0.21.5.tgz",
936 | "integrity": "sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==",
937 | "requires": {
938 | "ast-types": "0.15.2",
939 | "esprima": "~4.0.0",
940 | "source-map": "~0.6.1",
941 | "tslib": "^2.0.1"
942 | }
943 | },
944 | "rimraf": {
945 | "version": "2.6.3",
946 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
947 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
948 | "requires": {
949 | "glob": "^7.1.3"
950 | }
951 | },
952 | "semver": {
953 | "version": "6.3.0",
954 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
955 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
956 | },
957 | "shallow-clone": {
958 | "version": "3.0.1",
959 | "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
960 | "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
961 | "requires": {
962 | "kind-of": "^6.0.2"
963 | }
964 | },
965 | "signal-exit": {
966 | "version": "3.0.7",
967 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
968 | "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
969 | },
970 | "source-map": {
971 | "version": "0.6.1",
972 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
973 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
974 | },
975 | "source-map-support": {
976 | "version": "0.5.21",
977 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
978 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
979 | "requires": {
980 | "buffer-from": "^1.0.0",
981 | "source-map": "^0.6.0"
982 | }
983 | },
984 | "supports-color": {
985 | "version": "5.5.0",
986 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
987 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
988 | "requires": {
989 | "has-flag": "^3.0.0"
990 | }
991 | },
992 | "temp": {
993 | "version": "0.8.4",
994 | "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz",
995 | "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==",
996 | "requires": {
997 | "rimraf": "~2.6.2"
998 | }
999 | },
1000 | "to-fast-properties": {
1001 | "version": "2.0.0",
1002 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
1003 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="
1004 | },
1005 | "to-regex-range": {
1006 | "version": "5.0.1",
1007 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1008 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1009 | "requires": {
1010 | "is-number": "^7.0.0"
1011 | }
1012 | },
1013 | "tslib": {
1014 | "version": "2.5.0",
1015 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
1016 | "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
1017 | },
1018 | "update-browserslist-db": {
1019 | "version": "1.0.10",
1020 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
1021 | "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
1022 | "requires": {
1023 | "escalade": "^3.1.1",
1024 | "picocolors": "^1.0.0"
1025 | }
1026 | },
1027 | "wrappy": {
1028 | "version": "1.0.2",
1029 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1030 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
1031 | },
1032 | "write-file-atomic": {
1033 | "version": "2.4.3",
1034 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
1035 | "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
1036 | "requires": {
1037 | "graceful-fs": "^4.1.11",
1038 | "imurmurhash": "^0.1.4",
1039 | "signal-exit": "^3.0.2"
1040 | }
1041 | },
1042 | "yallist": {
1043 | "version": "3.1.1",
1044 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
1045 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
1046 | }
1047 | }
1048 | }
1049 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chromeos-key-remapper",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "background.js",
6 | "dependencies": {
7 | "jscodeshift": "^0.14.0"
8 | },
9 | "devDependencies": {},
10 | "scripts": {
11 | "test": "echo \"Error: no test specified\" && exit 1"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/ento/chromeos-key-remapper.git"
16 | },
17 | "author": "",
18 | "license": "ISC",
19 | "bugs": {
20 | "url": "https://github.com/ento/chromeos-key-remapper/issues"
21 | },
22 | "homepage": "https://github.com/ento/chromeos-key-remapper#readme"
23 | }
24 |
--------------------------------------------------------------------------------
/remapper/engine.js:
--------------------------------------------------------------------------------
1 | Remapper.Engine = function (keymap) {
2 | var contextId = -1;
3 | var lastFocusedWindowUrl = null;
4 | const debug = false;
5 |
6 | const urlBlacklist = [
7 | 'chrome-extension://pnhechapfaindjhompbnflcldabbghjo/html/crosh.html'
8 | ];
9 |
10 | const nullKeyData = {
11 | 'altKey': false,
12 | 'ctrlKey': false,
13 | 'shiftKey': false,
14 | 'key': '',
15 | 'code': ''
16 | };
17 |
18 | const sequencePrefixToKeyDataAttribute = {
19 | 'C-': 'ctrlKey',
20 | 'S-': 'shiftKey',
21 | 'M-': 'altKey'
22 | }
23 |
24 | function keyDataToSequenceString(keyData) {
25 | var sequence = '';
26 | if (keyData.ctrlKey) {
27 | sequence += 'C-';
28 | }
29 | if (keyData.shiftKey) {
30 | sequence += 'S-';
31 | }
32 | if (keyData.altKey) {
33 | sequence += 'M-';
34 | }
35 | sequence += keyData.key;
36 | return sequence;
37 | }
38 |
39 | function sequenceStringToKeyData(sequence) {
40 | var keyData = {};
41 | sequence.split(/(C-|M-|S-)/).forEach(function(part) {
42 | if (part.length == 0) {
43 | return;
44 | }
45 | var booleanAttribute = sequencePrefixToKeyDataAttribute[part];
46 | if (booleanAttribute) {
47 | keyData[booleanAttribute] = true;
48 | return;
49 | }
50 | // TODO: validate part is valid as code
51 | // Note: allegedly, only the `code` matters when using the `sendKeyEvents` API.
52 | keyData.code = part;
53 | });
54 | return keyData;
55 | }
56 |
57 | // grab the last focused window's URL for blacklisting. note that there will
58 | // be a delay due to the API being async.
59 | this.handleFocus = function(context) {
60 | contextId = context.contextID;
61 | chrome.windows.getLastFocused({
62 | populate: true,
63 | windowTypes: ['popup', 'normal', 'panel', 'app', 'devtools']
64 | }, function(window) {
65 | if (window && window.tabs.length > 0) {
66 | lastFocusedWindowUrl = window.tabs[0].url;
67 | }
68 | });
69 | }
70 |
71 | this.handleKeyEvent = function(engineID, keyData) {
72 | if (keyData.type === "keydown") {
73 | if (debug) {
74 | console.log(keyData.type, keyData.key, keyData.code, keyData);
75 | }
76 | }
77 |
78 | if (keyData.extensionId && (keyData.extensionId === chrome.runtime.id)) {
79 | // already remapped, pass it through
80 | return false;
81 | }
82 |
83 | if (lastFocusedWindowUrl && urlBlacklist.indexOf(lastFocusedWindowUrl) !== -1) {
84 | // don't remap in blacklisted windows
85 | return false;
86 | }
87 |
88 | var handled = false;
89 |
90 | if (keyData.type === "keydown") {
91 | var encodedSequence = keyDataToSequenceString(keyData);
92 |
93 | // TODO: convert keymap to an object of {match: decodedSequences} for speed
94 | var activeMapping = keymap.find(function(candidate) {
95 | return encodedSequence === candidate.match;
96 | });
97 |
98 | if (activeMapping) {
99 | var newKeyData = activeMapping.emit.map(function(sequence) {
100 | var mappedKeyData = sequenceStringToKeyData(sequence);
101 | return Object.assign({}, keyData, nullKeyData, mappedKeyData);
102 | });
103 | chrome.input.ime.sendKeyEvents({"contextID": contextId, "keyData": newKeyData});
104 | handled = true;
105 | }
106 | }
107 |
108 | return handled;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/remapper/keymap.js:
--------------------------------------------------------------------------------
1 | // bindings for emacs-like cursor movements.
2 | // variable name must match what's referenced in main.js.
3 | // TODO: better documentation on what values are accepted.
4 | const keymap = [
5 | {'match': 'C-a', 'emit': ['Home']}, // cursor: beginning of line
6 | {'match': 'C-e', 'emit': ['End']}, // cursor: end of line
7 | {'match': 'C-f', 'emit': ['ArrowRight']}, // cursor: forward one character
8 | {'match': 'C-b', 'emit': ['ArrowLeft']}, // cursor: back one character
9 | {'match': 'C-p', 'emit': ['ArrowUp']}, // cursor: previous line
10 | {'match': 'C-n', 'emit': ['ArrowDown']}, // cursor: next line
11 | {'match': 'C-k', 'emit': ['S-End', 'Backspace']}, // cursor: cut to end of line
12 | {'match': 'C-h', 'emit': ['Backspace']}, // cursor: backspace
13 | {'match': 'C-d', 'emit': ['Delete']}, // cursor: delete one char
14 | {'match': 'M-a', 'emit': ['C-KeyA']}, // C-a replacement: for select all
15 | {'match': 'M-b', 'emit': ['C-KeyB']}, // C-b replacement: for boldening text on paper
16 | {'match': 'M-n', 'emit': ['C-KeyN']}, // C-n replacement: for opening a new window
17 | {'match': 'M-k', 'emit': ['C-KeyK']} // C-k replacement: for Slack channel switcher
18 | ];
19 |
--------------------------------------------------------------------------------
/remapper/main.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var remapper = new Remapper.Engine(keymap);
3 | Remapper.hijack.onFocus.addListener(remapper.handleFocus.bind(remapper));
4 | Remapper.hijack.onKeyEvent.addListener(remapper.handleKeyEvent.bind(remapper));
5 | })();
6 |
--------------------------------------------------------------------------------
/remapper/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "US keyboard x emacs",
3 | "version": "1.0",
4 | "manifest_version": 2,
5 | "description": "US keyboard with emacs-like cursor movement",
6 | "background": {
7 | "scripts": [
8 | "preamble.js",
9 | "engine.js",
10 | "keymap.js",
11 | "main.js"
12 | ]
13 | },
14 | "permissions": [
15 | "input", "tabs"
16 | ],
17 | "input_components": [
18 | {
19 | "name": "US x emacs",
20 | "type": "ime",
21 | "id": "io.github.ento.cros_key_remapper",
22 | "description": "US keyboard with emacs-like cursor movement",
23 | "language": "en-US",
24 | "layouts": ["us"]
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/remapper/preamble.js:
--------------------------------------------------------------------------------
1 | const Remapper = {};
2 |
3 | // Acts as a middleman that accepts an chrome.input.ime event and
4 | // feeds it to registered event listeners. First listener to register
5 | // gets to handle the event first.
6 | Remapper.EventHandler = function EventHandler() {
7 | this.listeners = []
8 | };
9 |
10 | Remapper.EventHandler.prototype.addListener = function(fn) {
11 | this.listeners.push(fn)
12 | };
13 |
14 | Remapper.EventHandler.prototype.handleEvent = function() {
15 | let handled = false;
16 | for (let listener of this.listeners) {
17 | handled = listener.apply(null, arguments);
18 | if (handled) break;
19 | }
20 | return handled;
21 | };
22 |
23 | // Array of events to hijack.
24 | // see: https://developer.chrome.com/extensions/input_ime
25 | Remapper.events = [
26 | 'onActivate',
27 | 'onDeactivated',
28 | 'onFocus',
29 | 'onBlur',
30 | 'onInputContextUpdate',
31 | 'onKeyEvent',
32 | 'onCandidateClicked',
33 | 'onMenuItemActivated',
34 | 'onSurroundingTextChanged',
35 | 'onReset'
36 | // 'onCompositionBoundsChanged' // appears to be private
37 | ];
38 |
39 | // Name must match what's in hijack.js
40 | Remapper.hijack = {};
41 |
42 | Remapper.events.forEach(function(event) {
43 | const handler = new Remapper.EventHandler()
44 | Remapper.hijack[event] = handler;
45 | // The entire plot hinges on this `addListener` call not being
46 | // picked up by hijack.js, because this extension is just another
47 | // ime to be composed together with fallback imes.
48 | chrome.input.ime[event].addListener(handler.handleEvent.bind(handler));
49 | })
50 |
--------------------------------------------------------------------------------
/wscript:
--------------------------------------------------------------------------------
1 | import configparser
2 | from collections import OrderedDict
3 |
4 | from waflib import Task
5 | from waflib.TaskGen import feature, after_method
6 |
7 |
8 | top = '.'
9 | out = 'build'
10 |
11 | required_configs = [
12 | 'name',
13 | 'description',
14 | 'language',
15 | 'layout',
16 | 'fallback_imes',
17 | 'options_page',
18 | ]
19 |
20 |
21 | def configure(ctx):
22 | ctx.find_program('jscodeshift')
23 |
24 |
25 | def build(ctx):
26 | config = _read_config()
27 | for name in config:
28 | _build_ime(ctx, name, config[name])
29 |
30 |
31 | def _read_config():
32 | parser = configparser.ConfigParser()
33 | parser.read('config.ini')
34 | config = OrderedDict()
35 | for name in parser.sections():
36 | spec = {}
37 | for prop in required_configs:
38 | # TODO: more human-friendly error
39 | spec[prop] = parser[name][prop]
40 | spec['fallback_imes'] = [ime_name.strip()
41 | for ime_name in spec['fallback_imes'].split(',')
42 | if len(ime_name.strip()) > 0]
43 | config[name] = spec
44 | return config
45 |
46 |
47 | def _build_ime(ctx, name, spec):
48 | out = ctx.bldnode.find_or_declare(name)
49 |
50 | # copy / transform sources
51 |
52 | imes_root = ctx.path.find_dir('imes')
53 | transformer = ctx.path.find_node('hijack.js')
54 |
55 | # remapper must be the first in stack in order for hijacking to work.
56 | ime_stack = ['remapper'] + spec['fallback_imes']
57 | for ime_name in ime_stack:
58 | extension_root = imes_root.find_dir(ime_name)
59 | for extension_file in extension_root.ant_glob('**/*'):
60 | is_javascript = extension_file.suffix() == '.js'
61 | source = extension_file
62 | target = out.find_or_declare(extension_file.path_from(imes_root))
63 | if is_javascript:
64 | jscodeshift_env = ctx.env.derive()
65 | jscodeshift_env.TRANSFORMER = transformer.abspath()
66 | jscodeshift_task = jscodeshift(env=jscodeshift_env)
67 | jscodeshift_task.set_inputs(source)
68 | jscodeshift_task.set_outputs(target)
69 | ctx.add_to_group(jscodeshift_task)
70 | ctx.add_manual_dependency(source, transformer)
71 | else:
72 | ctx(features='subst',
73 | is_copy=True,
74 | source=source,
75 | target=target)
76 |
77 | # build manifest
78 |
79 | manifests = [out.find_or_declare(ime_name).find_or_declare('manifest.json')
80 | for ime_name in ime_stack]
81 | manifest_env = ctx.env.derive()
82 | manifest_env.identifier = name
83 | manifest_env.name = spec['name']
84 | manifest_env.description = spec['description']
85 | manifest_env.language = spec['language']
86 | manifest_env.layout = spec['layout']
87 | manifest_env.options_page = spec['options_page']
88 | manifest_task = manifest(env=manifest_env)
89 | manifest_task.set_inputs(manifests)
90 | manifest_task.set_outputs(out.find_or_declare('manifest.json'))
91 | ctx.add_to_group(manifest_task)
92 |
93 |
94 | class jscodeshift(Task.Task):
95 | run_str = 'node ${TRANSFORMER} ${SRC} ${TGT}'
96 |
97 |
98 | class manifest(Task.Task):
99 | '''
100 | Builds a manifest JSON by collecting background scripts and permissions
101 | from input files and reading the name, description, language, and layout
102 | from `self.env`.
103 | '''
104 |
105 | def run(self):
106 | target = self.outputs[0]
107 | out = target.parent
108 | submanifests = OrderedDict([(path, path.read_json()) for path in self.inputs])
109 |
110 | scripts = [path.parent.find_or_declare(script).path_from(out)
111 | for path, submanifest in submanifests.items()
112 | for script in submanifest['background']['scripts']]
113 |
114 | permissions = [permission
115 | for path, submanifest in submanifests.items()
116 | for permission in submanifest['permissions']]
117 |
118 | input_component = {
119 | "name": self.env.name,
120 | "type": "ime",
121 | "id": "io.github.ento.cros_key_remapper." + self.env.identifier,
122 | "description": self.env.description,
123 | "language": self.env.language,
124 | "layouts": [self.env.layout],
125 | }
126 | manifest = {
127 | "name": self.env.name,
128 | "version": "1.0",
129 | "manifest_version": 2,
130 | "description": self.env.description,
131 | "background": {
132 | "scripts": scripts,
133 | },
134 | "permissions": list(set(permissions)),
135 | "input_components": [
136 | input_component
137 | ]
138 | }
139 | if self.env.options_page:
140 | manifest['options_page'] = self.env.options_page
141 | target.write_json(manifest)
142 |
143 |
144 | def imes(ctx):
145 | imes_root = ctx.path.find_dir('imes')
146 | for extension_root in imes.ant_glob('*', src=False, dir=True):
147 | print(extension_root.path_from(imes_root))
148 |
--------------------------------------------------------------------------------