├── .gitignore ├── examples ├── sync-generator │ ├── index.html │ ├── worker │ │ └── index.mjs │ └── index.mjs ├── custom-sync-iterable │ ├── index.html │ ├── index.mjs │ └── worker │ │ └── index.mjs ├── simple-async-generator-iterable │ ├── index.html │ ├── worker │ │ └── index.mjs │ └── index.mjs ├── subscription-based-async-iterator │ ├── index.html │ ├── worker │ │ └── index.mjs │ └── index.mjs ├── generator-providing-values │ ├── index.html │ ├── worker │ │ └── index.mjs │ └── index.mjs └── more-complex-async-generator-iterable │ ├── index.html │ ├── worker │ └── index.mjs │ └── index.mjs ├── package.json ├── LICENSE ├── README.md ├── src └── iterableTransferHandlers.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .DS_STORE 4 | -------------------------------------------------------------------------------- /examples/sync-generator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Comlink test 7 | 8 | 9 | 10 |

11 | Click next to increment the value by 2. Uses a sync generator running in 12 | the Web worker. 13 |

14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/custom-sync-iterable/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Comlink test 7 | 8 | 9 | 10 |

11 | This example calls a custom iterable object using `for-await-of` and 12 | prints the sequence to the console. 13 |

14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/simple-async-generator-iterable/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Comlink test 7 | 8 | 9 | 10 |

11 | Click start to begin iterating over an async generator that sleeps for 1 12 | second between increments. 13 |

14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/subscription-based-async-iterator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Comlink test 7 | 8 | 9 | 10 |

11 | Click stop to cancel iterating over the stream of mock stock data by 12 | calling iterator's return function. 13 |

14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "comlink-async-iterators", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "Sam Burnstone", 6 | "license": "MIT", 7 | "scripts": { 8 | "start": "npx serve ." 9 | }, 10 | "devDependencies": { 11 | "husky": "^4.2.3", 12 | "prettier": "1.19.1", 13 | "pretty-quick": "^2.0.1" 14 | }, 15 | "husky": { 16 | "hooks": { 17 | "pre-commit": "pretty-quick --staged" 18 | } 19 | }, 20 | "dependencies": { 21 | "comlink": "^4.2.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/generator-providing-values/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Comlink test 7 | 8 | 9 | 10 |

11 | This example calls the iterator methods directly, passing a value into the 12 | `next` function. Check the console for the results. 13 |

14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/sync-generator/worker/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | expose, 3 | transferHandlers 4 | } from "../../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { iterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("iterable", iterableTransferHandler); 8 | 9 | function* strider() { 10 | const stride = 2; 11 | let index = 0; 12 | while (true) { 13 | index += stride; 14 | yield index; 15 | } 16 | } 17 | 18 | const exports = { 19 | strider 20 | }; 21 | 22 | expose(exports); 23 | -------------------------------------------------------------------------------- /examples/generator-providing-values/worker/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | expose, 3 | transferHandlers 4 | } from "../../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { iterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("iterable", iterableTransferHandler); 8 | 9 | function* createFamousPeopleGenerator() { 10 | const famousPeople = ["The Pope", "Victoria Beckham", "Michael Owen"]; 11 | for (const person of famousPeople) { 12 | const verdict = yield person; 13 | console.log(`Verdict on ${person}: ${verdict}`); 14 | } 15 | } 16 | 17 | const exports = { 18 | createFamousPeopleGenerator 19 | }; 20 | 21 | expose(exports); 22 | -------------------------------------------------------------------------------- /examples/custom-sync-iterable/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | transferHandlers, 3 | wrap 4 | } from "../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { iterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("iterable", iterableTransferHandler); 8 | 9 | const worker = wrap(new Worker("./worker/index.mjs", { type: "module" })); 10 | 11 | (async () => { 12 | const iterable = await worker.makeStrider(); 13 | 14 | // Direct access of iterable - no work. Is this because there's a sync lookup behind the scenes? 15 | for await (const value of iterable) { 16 | if (value > 20) { 17 | return; 18 | } 19 | 20 | console.log(value); 21 | } 22 | })(); 23 | -------------------------------------------------------------------------------- /examples/more-complex-async-generator-iterable/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Comlink test 7 | 8 | 9 | 10 |

11 | This example uses an async iterator to fetch the 100 most recent commits 12 | from the Swift repo. Click start to begin. 13 |

14 |

15 | Example heavily inspired by 16 | javascript.info 20 |

21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/subscription-based-async-iterator/worker/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | expose, 3 | transferHandlers 4 | } from "../../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { asyncIterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("asyncIterable", asyncIterableTransferHandler); 8 | 9 | let shouldCount = false; 10 | 11 | const sleep = () => 12 | new Promise(res => { 13 | setTimeout(res, 1000); 14 | }); 15 | 16 | async function* startSubscription(stockSymbol) { 17 | let currentPrice = Math.random() * 50; 18 | while (true) { 19 | currentPrice += Math.random(); 20 | yield currentPrice; 21 | await sleep(); 22 | } 23 | } 24 | 25 | const exports = { 26 | startSubscription 27 | }; 28 | 29 | expose(exports); 30 | -------------------------------------------------------------------------------- /examples/custom-sync-iterable/worker/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | expose, 3 | transferHandlers 4 | } from "../../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { iterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("iterable", iterableTransferHandler); 8 | 9 | const makeStrider = () => { 10 | const stride = 2; 11 | 12 | return { 13 | sum: (a, b) => { 14 | return a + b; 15 | }, 16 | [Symbol.iterator]: () => { 17 | let index = 0; 18 | return { 19 | next: () => { 20 | index += stride; 21 | return { 22 | value: index, 23 | done: false 24 | }; 25 | } 26 | }; 27 | } 28 | }; 29 | }; 30 | 31 | const exports = { 32 | makeStrider 33 | }; 34 | 35 | expose(exports); 36 | -------------------------------------------------------------------------------- /examples/sync-generator/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | wrap, 3 | transferHandlers 4 | } from "../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { iterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("iterable", iterableTransferHandler); 8 | 9 | const worker = wrap(new Worker("./worker/index.mjs", { type: "module" })); 10 | 11 | (async () => { 12 | const strider = await worker.strider(); 13 | 14 | const button = document.createElement("button"); 15 | button.innerText = "Next"; 16 | 17 | const counterEl = document.createElement("p"); 18 | document.body.appendChild(counterEl); 19 | 20 | button.addEventListener("click", async () => { 21 | const { value } = await strider.next(); 22 | counterEl.innerText = value; 23 | }); 24 | document.body.appendChild(button); 25 | })(); 26 | -------------------------------------------------------------------------------- /examples/simple-async-generator-iterable/worker/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | expose, 3 | transferHandlers 4 | } from "../../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { asyncIterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("asyncIterable", asyncIterableTransferHandler); 8 | 9 | let shouldCount = false; 10 | 11 | const sleep = () => 12 | new Promise(res => { 13 | setTimeout(res, 1000); 14 | }); 15 | 16 | async function* start() { 17 | shouldCount = true; 18 | let counter = 0; 19 | while (shouldCount) { 20 | yield counter++; 21 | await sleep(); 22 | } 23 | } 24 | 25 | // TODO: do we need to inform other way where the generator exits. 26 | const stop = () => { 27 | shouldCount = false; 28 | }; 29 | 30 | const exports = { 31 | start, 32 | stop 33 | }; 34 | 35 | expose(exports); 36 | -------------------------------------------------------------------------------- /examples/more-complex-async-generator-iterable/worker/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | expose, 3 | transferHandlers 4 | } from "../../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { asyncIterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("asyncIterable", asyncIterableTransferHandler); 8 | 9 | async function* fetchCommits(repo) { 10 | let url = `https://api.github.com/repos/${repo}/commits`; 11 | 12 | while (url) { 13 | const response = await fetch(url); 14 | 15 | const body = await response.json(); 16 | 17 | let nextPage = response.headers.get("Link").match(/<(.*?)>; rel="next"/); 18 | nextPage = nextPage && nextPage[1]; 19 | 20 | url = nextPage; 21 | 22 | for (let commit of body) { 23 | yield commit; 24 | } 25 | } 26 | } 27 | 28 | const exports = { 29 | fetchCommits 30 | }; 31 | 32 | expose(exports); 33 | -------------------------------------------------------------------------------- /examples/generator-providing-values/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | wrap, 3 | transferHandlers 4 | } from "../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { iterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("iterable", iterableTransferHandler); 8 | 9 | const worker = wrap(new Worker("./worker/index.mjs", { type: "module" })); 10 | 11 | (async () => { 12 | const famousPeopleGenerator = await worker.createFamousPeopleGenerator(); 13 | 14 | // First time calling next arg will be ignored (returns Pope as value) 15 | console.log(await famousPeopleGenerator.next()); 16 | // While our arg is referring to the pope, the value being returned is Victoria Beckham 17 | console.log(await famousPeopleGenerator.next("Don't know him that well")); 18 | console.log(await famousPeopleGenerator.next("Not a fan...")); 19 | console.log(await famousPeopleGenerator.next("Almost forgot about him!")); 20 | })(); 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sam Burnstone 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 | -------------------------------------------------------------------------------- /examples/subscription-based-async-iterator/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | wrap, 3 | transferHandlers 4 | } from "../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { asyncIterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("asyncIterable", asyncIterableTransferHandler); 8 | 9 | const subscriptionService = wrap( 10 | new Worker("./worker/index.mjs", { type: "module" }) 11 | ); 12 | 13 | const startSubscription = async stockSymbol => { 14 | const priceEl = document.createElement("p"); 15 | priceEl.innerText = `${stockSymbol}: -`; 16 | document.body.appendChild(priceEl); 17 | 18 | const stopButtonEl = document.createElement("button"); 19 | stopButtonEl.innerText = "Stop!"; 20 | document.body.appendChild(stopButtonEl); 21 | 22 | const iterator = await subscriptionService.startSubscription(stockSymbol); 23 | 24 | stopButtonEl.addEventListener("click", () => { 25 | iterator.return(); 26 | stopButtonEl.disabled = true; 27 | }); 28 | 29 | for await (const price of iterator) { 30 | priceEl.innerText = `${stockSymbol}: ${price.toFixed(2)}`; 31 | } 32 | }; 33 | 34 | startSubscription("TSLA"); 35 | startSubscription("APPL"); 36 | startSubscription("IBM"); 37 | -------------------------------------------------------------------------------- /examples/more-complex-async-generator-iterable/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | wrap, 3 | transferHandlers 4 | } from "../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { asyncIterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("asyncIterable", asyncIterableTransferHandler); 8 | 9 | const commitFetcher = wrap( 10 | new Worker("./worker/index.mjs", { type: "module" }) 11 | ); 12 | 13 | const startFetching = async () => { 14 | let count = 0; 15 | 16 | for await (const commit of await commitFetcher.fetchCommits("apple/swift")) { 17 | const commitAuthor = !!commit.author 18 | ? commit.author.login 19 | : "Author not available"; 20 | 21 | const authorElement = document.createElement("p"); 22 | authorElement.innerText = commitAuthor; 23 | document.body.appendChild(authorElement); 24 | 25 | if (++count === 100) { 26 | // 100 commits is quite enough 27 | break; 28 | } 29 | } 30 | }; 31 | 32 | const button = document.createElement("button"); 33 | button.innerText = "Start"; 34 | 35 | button.addEventListener("click", async () => { 36 | startFetching(); 37 | button.style.display = "none"; 38 | }); 39 | document.body.appendChild(button); 40 | -------------------------------------------------------------------------------- /examples/simple-async-generator-iterable/index.mjs: -------------------------------------------------------------------------------- 1 | import { 2 | wrap, 3 | transferHandlers 4 | } from "../../node_modules/comlink/dist/esm/comlink.mjs"; 5 | import { asyncIterableTransferHandler } from "../../../src/iterableTransferHandlers.js"; 6 | 7 | transferHandlers.set("asyncIterable", asyncIterableTransferHandler); 8 | 9 | const worker = new Worker("./worker/index.mjs", { type: "module" }); 10 | 11 | let isCounting = false; 12 | const counter = wrap(worker); 13 | 14 | const startCounter = async () => { 15 | const iterable = await counter.start(); 16 | 17 | for await (const value of iterable) { 18 | const el = document.querySelector("p.target"); 19 | el.innerText = value; 20 | 21 | if (value === 10) { 22 | break; 23 | } 24 | } 25 | isCounting = false; 26 | updateButtonTitle(); 27 | }; 28 | 29 | const button = document.createElement("button"); 30 | 31 | const updateButtonTitle = () => 32 | (button.innerText = isCounting ? "Stop" : "Start"); 33 | 34 | updateButtonTitle(); 35 | button.addEventListener("click", async () => { 36 | if (!isCounting) { 37 | startCounter(); 38 | } else { 39 | await counter.stop(); 40 | isCounting = false; 41 | updateButtonTitle(); 42 | } 43 | 44 | isCounting = !isCounting; 45 | updateButtonTitle(); 46 | }); 47 | document.body.appendChild(button); 48 | 49 | // Counter paragraph 50 | const counterEl = document.createElement("p"); 51 | counterEl.classList.add("target"); 52 | document.body.appendChild(counterEl); 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cross-window async iterators using Comlink 2 | 3 | Uses Comlink's `transferHandler` pluggable functionality to add support for async and sync iterables to be called from a different browser execution context. 4 | 5 | This repository accompanies [this blog post](https://blog.scottlogic.com/2020/04/22/Async-Iterators-Across-Execution-Contexts.html) which I hope you find informative. Note that you may want to take a look at [this Comlink issue](https://github.com/GoogleChromeLabs/comlink/issues/435) where there's a discussion about how to get generators working using the library. 6 | 7 | ## Running the examples 8 | 9 | A number of different iterable use-cases were trialled to check the transfer handler worked in these cases. You can view these examples by doing the following: 10 | 11 | - `yarn install` 12 | - `yarn start` - This will start a server running on `localhost:5000` 13 | - Navigate to `localhost:5000/examples` 14 | 15 | Note that the examples are written using ES6 modules in Web Workers - this requires Chrome 80 ([Firefox and Safari don't yet support this](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Browser_compatibility)). 16 | 17 | ## Shortcomings 18 | 19 | - Currently, only the iterator / async iterator is callable "over the wire". This means any other properties available on the iterable cannot be accessed. 20 | - If an object is both sync and async iterable, only one will be transferred. Which one is chosen will depend on the order the transfer handlers are added (first one added will have priority). 21 | - I've tested it with a decent range of use-cases, however there are likely many more that I haven't considered. Feel free to raise an issue / PR if you have any questions. 22 | -------------------------------------------------------------------------------- /src/iterableTransferHandlers.js: -------------------------------------------------------------------------------- 1 | const MESSAGE_TYPES = { 2 | NEXT: "NEXT", 3 | RETURN: "RETURN", 4 | THROW: "THROW", 5 | DEFINED_OPTIONAL_ITERATOR_FNS: "DEFINED_OPTIONAL_ITERATOR_FNS" 6 | }; 7 | 8 | const listen = async (iterator, port) => { 9 | port.onmessage = async ({ data: { type, value } }) => { 10 | switch (type) { 11 | case MESSAGE_TYPES.NEXT: 12 | port.postMessage(await iterator.next(value)); 13 | break; 14 | case MESSAGE_TYPES.RETURN: 15 | port.postMessage(await iterator.return(value)); 16 | break; 17 | case MESSAGE_TYPES.THROW: 18 | port.postMessage(await iterator.throw(value)); 19 | } 20 | }; 21 | }; 22 | 23 | const makeTransferHandler = symbolLookup => ({ 24 | canHandle: obj => { 25 | return obj && obj[symbolLookup]; 26 | }, 27 | serialize: iterable => { 28 | const { port1, port2 } = new MessageChannel(); 29 | 30 | const iterator = iterable[symbolLookup](); 31 | 32 | const definedOptionalIteratorFns = { 33 | throw: !!iterator.throw, 34 | return: !!iterator.return 35 | }; 36 | 37 | port1.postMessage({ 38 | type: MESSAGE_TYPES.DEFINED_OPTIONAL_ITERATOR_FNS, 39 | value: definedOptionalIteratorFns 40 | }); 41 | 42 | listen(iterator, port1); 43 | return [port2, [port2]]; 44 | }, 45 | deserialize: async port => { 46 | const nextPortMessage = () => 47 | new Promise(resolve => { 48 | port.onmessage = ({ data }) => { 49 | resolve(data); 50 | }; 51 | }); 52 | 53 | // First message to come back will advertise functions defined on iterator 54 | const { value: availableIteratorFns } = await nextPortMessage(); 55 | 56 | // Cover the case where a user wants to be able to manually call the iterator methods 57 | const iterator = { 58 | next: value => { 59 | port.postMessage({ type: MESSAGE_TYPES.NEXT, value }); 60 | return nextPortMessage(); 61 | } 62 | }; 63 | 64 | // return and throw functions are optional (https://tc39.es/ecma262/#table-async-iterator-optional), 65 | // so we check they're available 66 | if (availableIteratorFns.return) { 67 | iterator.return = value => { 68 | port.postMessage({ type: MESSAGE_TYPES.RETURN, value }); 69 | return nextPortMessage(); 70 | }; 71 | } 72 | 73 | if (availableIteratorFns.throw) { 74 | iterator.throw = async value => { 75 | port.postMessage({ type: MESSAGE_TYPES.THROW, value }); 76 | return nextPortMessage(); 77 | }; 78 | } 79 | 80 | // Make it iterable so it can be used in for-await-of statement 81 | iterator[Symbol.asyncIterator] = () => iterator; 82 | 83 | return iterator; 84 | } 85 | }); 86 | 87 | const asyncIterableTransferHandler = makeTransferHandler(Symbol.asyncIterator); 88 | const iterableTransferHandler = makeTransferHandler(Symbol.iterator); 89 | 90 | export { asyncIterableTransferHandler, iterableTransferHandler }; 91 | -------------------------------------------------------------------------------- /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.8.3" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" 8 | integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== 9 | dependencies: 10 | "@babel/highlight" "^7.8.3" 11 | 12 | "@babel/highlight@^7.8.3": 13 | version "7.8.3" 14 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" 15 | integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== 16 | dependencies: 17 | chalk "^2.0.0" 18 | esutils "^2.0.2" 19 | js-tokens "^4.0.0" 20 | 21 | "@babel/runtime@^7.8.7": 22 | version "7.8.7" 23 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.7.tgz#8fefce9802db54881ba59f90bb28719b4996324d" 24 | integrity sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg== 25 | dependencies: 26 | regenerator-runtime "^0.13.4" 27 | 28 | "@types/color-name@^1.1.1": 29 | version "1.1.1" 30 | resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" 31 | integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== 32 | 33 | "@types/minimatch@^3.0.3": 34 | version "3.0.3" 35 | resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" 36 | integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== 37 | 38 | "@types/parse-json@^4.0.0": 39 | version "4.0.0" 40 | resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" 41 | integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== 42 | 43 | ansi-styles@^3.2.1: 44 | version "3.2.1" 45 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 46 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 47 | dependencies: 48 | color-convert "^1.9.0" 49 | 50 | ansi-styles@^4.1.0: 51 | version "4.2.1" 52 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" 53 | integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== 54 | dependencies: 55 | "@types/color-name" "^1.1.1" 56 | color-convert "^2.0.1" 57 | 58 | array-differ@^3.0.0: 59 | version "3.0.0" 60 | resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" 61 | integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== 62 | 63 | array-union@^2.1.0: 64 | version "2.1.0" 65 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" 66 | integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== 67 | 68 | arrify@^2.0.1: 69 | version "2.0.1" 70 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" 71 | integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== 72 | 73 | balanced-match@^1.0.0: 74 | version "1.0.0" 75 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 76 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 77 | 78 | brace-expansion@^1.1.7: 79 | version "1.1.11" 80 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 81 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 82 | dependencies: 83 | balanced-match "^1.0.0" 84 | concat-map "0.0.1" 85 | 86 | callsites@^3.0.0: 87 | version "3.1.0" 88 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 89 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 90 | 91 | chalk@^2.0.0, chalk@^2.4.2: 92 | version "2.4.2" 93 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 94 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 95 | dependencies: 96 | ansi-styles "^3.2.1" 97 | escape-string-regexp "^1.0.5" 98 | supports-color "^5.3.0" 99 | 100 | chalk@^3.0.0: 101 | version "3.0.0" 102 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" 103 | integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== 104 | dependencies: 105 | ansi-styles "^4.1.0" 106 | supports-color "^7.1.0" 107 | 108 | ci-info@^2.0.0: 109 | version "2.0.0" 110 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" 111 | integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== 112 | 113 | color-convert@^1.9.0: 114 | version "1.9.3" 115 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 116 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 117 | dependencies: 118 | color-name "1.1.3" 119 | 120 | color-convert@^2.0.1: 121 | version "2.0.1" 122 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 123 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 124 | dependencies: 125 | color-name "~1.1.4" 126 | 127 | color-name@1.1.3: 128 | version "1.1.3" 129 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 130 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 131 | 132 | color-name@~1.1.4: 133 | version "1.1.4" 134 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 135 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 136 | 137 | comlink@^4.2.0: 138 | version "4.2.0" 139 | resolved "https://registry.yarnpkg.com/comlink/-/comlink-4.2.0.tgz#be9e968a19d797a44a042cf1eac03775d2ed39fe" 140 | integrity sha512-33hF3yYzZicIWLREuvluTGSZkbAXYwRmrA9IYQo0/P+0O45qgvzR0FHX4tRZztObFMTs/RhnN0G0UBNDAZSiCg== 141 | 142 | compare-versions@^3.5.1: 143 | version "3.6.0" 144 | resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" 145 | integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== 146 | 147 | concat-map@0.0.1: 148 | version "0.0.1" 149 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 150 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 151 | 152 | cosmiconfig@^6.0.0: 153 | version "6.0.0" 154 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" 155 | integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== 156 | dependencies: 157 | "@types/parse-json" "^4.0.0" 158 | import-fresh "^3.1.0" 159 | parse-json "^5.0.0" 160 | path-type "^4.0.0" 161 | yaml "^1.7.2" 162 | 163 | cross-spawn@^7.0.0: 164 | version "7.0.1" 165 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" 166 | integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== 167 | dependencies: 168 | path-key "^3.1.0" 169 | shebang-command "^2.0.0" 170 | which "^2.0.1" 171 | 172 | end-of-stream@^1.1.0: 173 | version "1.4.4" 174 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 175 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 176 | dependencies: 177 | once "^1.4.0" 178 | 179 | error-ex@^1.3.1: 180 | version "1.3.2" 181 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 182 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 183 | dependencies: 184 | is-arrayish "^0.2.1" 185 | 186 | escape-string-regexp@^1.0.5: 187 | version "1.0.5" 188 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 189 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 190 | 191 | esutils@^2.0.2: 192 | version "2.0.3" 193 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 194 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 195 | 196 | execa@^2.1.0: 197 | version "2.1.0" 198 | resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99" 199 | integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw== 200 | dependencies: 201 | cross-spawn "^7.0.0" 202 | get-stream "^5.0.0" 203 | is-stream "^2.0.0" 204 | merge-stream "^2.0.0" 205 | npm-run-path "^3.0.0" 206 | onetime "^5.1.0" 207 | p-finally "^2.0.0" 208 | signal-exit "^3.0.2" 209 | strip-final-newline "^2.0.0" 210 | 211 | find-up@^4.0.0, find-up@^4.1.0: 212 | version "4.1.0" 213 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" 214 | integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== 215 | dependencies: 216 | locate-path "^5.0.0" 217 | path-exists "^4.0.0" 218 | 219 | find-versions@^3.2.0: 220 | version "3.2.0" 221 | resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" 222 | integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== 223 | dependencies: 224 | semver-regex "^2.0.0" 225 | 226 | get-stream@^5.0.0: 227 | version "5.1.0" 228 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" 229 | integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== 230 | dependencies: 231 | pump "^3.0.0" 232 | 233 | has-flag@^3.0.0: 234 | version "3.0.0" 235 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 236 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 237 | 238 | has-flag@^4.0.0: 239 | version "4.0.0" 240 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 241 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 242 | 243 | husky@^4.2.3: 244 | version "4.2.3" 245 | resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.3.tgz#3b18d2ee5febe99e27f2983500202daffbc3151e" 246 | integrity sha512-VxTsSTRwYveKXN4SaH1/FefRJYCtx+wx04sSVcOpD7N2zjoHxa+cEJ07Qg5NmV3HAK+IRKOyNVpi2YBIVccIfQ== 247 | dependencies: 248 | chalk "^3.0.0" 249 | ci-info "^2.0.0" 250 | compare-versions "^3.5.1" 251 | cosmiconfig "^6.0.0" 252 | find-versions "^3.2.0" 253 | opencollective-postinstall "^2.0.2" 254 | pkg-dir "^4.2.0" 255 | please-upgrade-node "^3.2.0" 256 | slash "^3.0.0" 257 | which-pm-runs "^1.0.0" 258 | 259 | ignore@^5.1.4: 260 | version "5.1.4" 261 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" 262 | integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== 263 | 264 | import-fresh@^3.1.0: 265 | version "3.2.1" 266 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" 267 | integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== 268 | dependencies: 269 | parent-module "^1.0.0" 270 | resolve-from "^4.0.0" 271 | 272 | is-arrayish@^0.2.1: 273 | version "0.2.1" 274 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 275 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= 276 | 277 | is-stream@^2.0.0: 278 | version "2.0.0" 279 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" 280 | integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== 281 | 282 | isexe@^2.0.0: 283 | version "2.0.0" 284 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 285 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 286 | 287 | js-tokens@^4.0.0: 288 | version "4.0.0" 289 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 290 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 291 | 292 | json-parse-better-errors@^1.0.1: 293 | version "1.0.2" 294 | resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" 295 | integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== 296 | 297 | lines-and-columns@^1.1.6: 298 | version "1.1.6" 299 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" 300 | integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= 301 | 302 | locate-path@^5.0.0: 303 | version "5.0.0" 304 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" 305 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== 306 | dependencies: 307 | p-locate "^4.1.0" 308 | 309 | merge-stream@^2.0.0: 310 | version "2.0.0" 311 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" 312 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== 313 | 314 | mimic-fn@^2.1.0: 315 | version "2.1.0" 316 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" 317 | integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 318 | 319 | minimatch@^3.0.4: 320 | version "3.0.4" 321 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 322 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 323 | dependencies: 324 | brace-expansion "^1.1.7" 325 | 326 | mri@^1.1.4: 327 | version "1.1.4" 328 | resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" 329 | integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== 330 | 331 | multimatch@^4.0.0: 332 | version "4.0.0" 333 | resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3" 334 | integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ== 335 | dependencies: 336 | "@types/minimatch" "^3.0.3" 337 | array-differ "^3.0.0" 338 | array-union "^2.1.0" 339 | arrify "^2.0.1" 340 | minimatch "^3.0.4" 341 | 342 | npm-run-path@^3.0.0: 343 | version "3.1.0" 344 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" 345 | integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== 346 | dependencies: 347 | path-key "^3.0.0" 348 | 349 | once@^1.3.1, once@^1.4.0: 350 | version "1.4.0" 351 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 352 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 353 | dependencies: 354 | wrappy "1" 355 | 356 | onetime@^5.1.0: 357 | version "5.1.0" 358 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" 359 | integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== 360 | dependencies: 361 | mimic-fn "^2.1.0" 362 | 363 | opencollective-postinstall@^2.0.2: 364 | version "2.0.2" 365 | resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" 366 | integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== 367 | 368 | p-finally@^2.0.0: 369 | version "2.0.1" 370 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" 371 | integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== 372 | 373 | p-limit@^2.2.0: 374 | version "2.2.2" 375 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" 376 | integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== 377 | dependencies: 378 | p-try "^2.0.0" 379 | 380 | p-locate@^4.1.0: 381 | version "4.1.0" 382 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" 383 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== 384 | dependencies: 385 | p-limit "^2.2.0" 386 | 387 | p-try@^2.0.0: 388 | version "2.2.0" 389 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 390 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 391 | 392 | parent-module@^1.0.0: 393 | version "1.0.1" 394 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 395 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 396 | dependencies: 397 | callsites "^3.0.0" 398 | 399 | parse-json@^5.0.0: 400 | version "5.0.0" 401 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" 402 | integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== 403 | dependencies: 404 | "@babel/code-frame" "^7.0.0" 405 | error-ex "^1.3.1" 406 | json-parse-better-errors "^1.0.1" 407 | lines-and-columns "^1.1.6" 408 | 409 | path-exists@^4.0.0: 410 | version "4.0.0" 411 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 412 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 413 | 414 | path-key@^3.0.0, path-key@^3.1.0: 415 | version "3.1.1" 416 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 417 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 418 | 419 | path-type@^4.0.0: 420 | version "4.0.0" 421 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 422 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 423 | 424 | pkg-dir@^4.2.0: 425 | version "4.2.0" 426 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" 427 | integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== 428 | dependencies: 429 | find-up "^4.0.0" 430 | 431 | please-upgrade-node@^3.2.0: 432 | version "3.2.0" 433 | resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" 434 | integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== 435 | dependencies: 436 | semver-compare "^1.0.0" 437 | 438 | prettier@1.19.1: 439 | version "1.19.1" 440 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" 441 | integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== 442 | 443 | pretty-quick@^2.0.1: 444 | version "2.0.1" 445 | resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-2.0.1.tgz#417ee605ade98ecc686e72f63b5d28a2c35b43e9" 446 | integrity sha512-y7bJt77XadjUr+P1uKqZxFWLddvj3SKY6EU4BuQtMxmmEFSMpbN132pUWdSG1g1mtUfO0noBvn7wBf0BVeomHg== 447 | dependencies: 448 | chalk "^2.4.2" 449 | execa "^2.1.0" 450 | find-up "^4.1.0" 451 | ignore "^5.1.4" 452 | mri "^1.1.4" 453 | multimatch "^4.0.0" 454 | 455 | pump@^3.0.0: 456 | version "3.0.0" 457 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 458 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 459 | dependencies: 460 | end-of-stream "^1.1.0" 461 | once "^1.3.1" 462 | 463 | regenerator-runtime@^0.13.4: 464 | version "0.13.5" 465 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" 466 | integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== 467 | 468 | resolve-from@^4.0.0: 469 | version "4.0.0" 470 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 471 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 472 | 473 | semver-compare@^1.0.0: 474 | version "1.0.0" 475 | resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" 476 | integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= 477 | 478 | semver-regex@^2.0.0: 479 | version "2.0.0" 480 | resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" 481 | integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== 482 | 483 | shebang-command@^2.0.0: 484 | version "2.0.0" 485 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 486 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 487 | dependencies: 488 | shebang-regex "^3.0.0" 489 | 490 | shebang-regex@^3.0.0: 491 | version "3.0.0" 492 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 493 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 494 | 495 | signal-exit@^3.0.2: 496 | version "3.0.2" 497 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 498 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 499 | 500 | slash@^3.0.0: 501 | version "3.0.0" 502 | resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" 503 | integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== 504 | 505 | strip-final-newline@^2.0.0: 506 | version "2.0.0" 507 | resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" 508 | integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== 509 | 510 | supports-color@^5.3.0: 511 | version "5.5.0" 512 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 513 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 514 | dependencies: 515 | has-flag "^3.0.0" 516 | 517 | supports-color@^7.1.0: 518 | version "7.1.0" 519 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" 520 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== 521 | dependencies: 522 | has-flag "^4.0.0" 523 | 524 | which-pm-runs@^1.0.0: 525 | version "1.0.0" 526 | resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" 527 | integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= 528 | 529 | which@^2.0.1: 530 | version "2.0.2" 531 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 532 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 533 | dependencies: 534 | isexe "^2.0.0" 535 | 536 | wrappy@1: 537 | version "1.0.2" 538 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 539 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 540 | 541 | yaml@^1.7.2: 542 | version "1.8.2" 543 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.8.2.tgz#a29c03f578faafd57dcb27055f9a5d569cb0c3d9" 544 | integrity sha512-omakb0d7FjMo3R1D2EbTKVIk6dAVLRxFXdLZMEUToeAvuqgG/YuHMuQOZ5fgk+vQ8cx+cnGKwyg+8g8PNT0xQg== 545 | dependencies: 546 | "@babel/runtime" "^7.8.7" 547 | --------------------------------------------------------------------------------