├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── README.md ├── build ├── batchql.d.ts ├── batchql.js ├── combinators.d.ts ├── combinators.js ├── merge.d.ts ├── merge.js ├── parsers.d.ts ├── parsers.js ├── regenerate.d.ts ├── regenerate.js ├── utils.d.ts └── utils.js ├── fuse.js ├── icon.svg ├── package.json ├── src ├── batchql.test.ts ├── batchql.ts ├── combinators.ts ├── merge.test.ts ├── merge.ts ├── parsers.ts ├── regenerate.ts ├── test-data.ts ├── test.html ├── test.ts ├── utils.test.ts └── utils.ts └── yarn.lock /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. Please see the project owner team for contact info. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this project 2 | 3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: 4 | 5 | The following is a set of guidelines for contributing to this project and its packages. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. 6 | 7 | #### Table Of Contents 8 | 9 | [What should I know before I get started?](#what-should-i-know-before-i-get-started) 10 | * [Code of Conduct](#code-of-conduct) 11 | 12 | [How Can I Contribute?](#how-can-i-contribute) 13 | * [Reporting Bugs](#reporting-bugs) 14 | * [Pull Requests](#pull-requests) 15 | 16 | ## What should I know before I get started? 17 | 18 | ### Code of Conduct 19 | 20 | This project adheres to the Contributor Covenant [code of conduct](./CODE_OF_CONDUCT.md). 21 | By participating, you are expected to uphold this code. 22 | Please report unacceptable behavior to the project owners. 23 | 24 | ## How Can I Contribute? 25 | 26 | ### Reporting Bugs 27 | 28 | This section guides you through submitting a bug report. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:. 29 | 30 | Bug reports have an [issue template](./ISSUE_TEMPLATE.md) included. Before creating bug reports, please check that you clearly answer all the needs for the issue. 31 | 32 | #### How Do I Submit A (Good) Bug Report? 33 | 34 | Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue on this repository and provide the following information: 35 | 36 | * **Use a clear and descriptive title** for the issue to identify the problem. 37 | * **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started, e.g. which command exactly you used in the terminal. When listing steps, **don't just say what you did, but explain how you did it**. For example, if you moved the cursor to the end of a line, explain if you used the mouse, or a keyboard shortcut or another command, and if so which one? 38 | * **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). 39 | * **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. 40 | * **Explain which behavior you expected to see instead and why.** 41 | * **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem. 42 | * **If you're reporting that this project crashed**, include a crash report with a stack trace from the operating system. On OSX, the crash report will be available in `Console.app` under "Diagnostic and usage information" > "User diagnostic reports". Include the crash report in the issue in a [code block](https://help.github.com/articles/markdown-basics/#multiple-lines), a [file attachment](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests/), or put it in a [gist](https://gist.github.com/) and provide link to that gist. 43 | * **If the problem is related to performance**, include a CPU profile capture and a screenshot with your report. 44 | * **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below. 45 | 46 | ### Pull Requests 47 | 48 | Submitting Pull Requests should be as detailed as [Reporting Bugs](#reporting-bugs). There is also a [Pull Request Template](./PULL_REQUEST_TEMPLATE.md) to follow, as guidelines. You'll need to fill out as much information as you can to assist the maintainers in assessing / testing your submission. 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | [Short description of problem here] 2 | 3 | **Reproduction Steps:** 4 | 5 | 1. [First Step] 6 | 2. [Second Step] 7 | 3. [Other Steps...] 8 | 9 | **Expected behavior:** 10 | 11 | [Describe expected behavior here] 12 | 13 | **Observed behavior:** 14 | 15 | [Describe observed behavior here] 16 | 17 | **Screenshots and GIFs** 18 | 19 | ![Screenshots and GIFs which follow reproduction steps to demonstrate the problem](url) 20 | 21 | **Atom version:** [Enter Atom version here] 22 | **OS and version:** [Enter OS name and version here] 23 | 24 | **Installed packages:** 25 | 26 | [List of installed packages here] 27 | 28 | **Additional information:** 29 | 30 | * Problem can be reproduced in safe mode: [Yes/No] 31 | * Problem started happening recently, didn't happen in an older version of Atom: [Yes/No] 32 | * Problem can be reliably reproduced, doesn't happen randomly: [Yes/No] 33 | * Problem happens with all files and projects, not only some files or projects: [Yes/No] -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - [ ] Ready for review? 2 | - [ ] Follows CONTRIBUTING rules? 3 | - [ ] Reviewed by Repo owners? 4 | 5 | #### What does this PR do? 6 | #### Where should the reviewer start? 7 | #### How should this be manually tested? 8 | #### Any background context you want to provide? 9 | #### What are the relevant tickets? 10 | #### Screenshots 11 | #### Additional questions -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log 3 | pids 4 | *.pid 5 | *.seed 6 | lib-cov 7 | coverage 8 | .grunt 9 | .lock-wscript 10 | build/*.json 11 | node_modules 12 | .fusebox 13 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.png 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BatchQL 2 | 3 | ![logo](./icon.svg) 4 | 5 | [![NPM](https://nodei.co/npm/batchql.png)](https://nodei.co/npm/batchql/) 6 | 7 | BatchQL is a language-level query optimizer for GraphQL. 8 | 9 | **Note:** Not all GraphQL features are perfectly supported, there will be some caveats that come with the usage of a tool like this. Right now, you should handle mutations and subscriptions through standard means, as the batching logic has been written with queries in mind. But mutations are really close to working :) 10 | 11 | ## Installation 12 | 13 | ```sh 14 | npm install --save batchql 15 | # or 16 | yarn add batchql 17 | ``` 18 | 19 | ## Playground & Usage 20 | 21 | You can play with the code by copy+pasting the following into https://matthiasak.github.io/arbiter-frame. This example uses the GitHub GraphQL API to demonstrate the effectiveness of logical query batching :) 22 | 23 | ```js 24 | const token = `${'4eb1f1a7b25729f6'}${'27d570e88688ef866017388e'}` 25 | 26 | const app = $ => { 27 | const {mux, batch, debug} = batchql 28 | 29 | const fetcher = (url) => (query, args) => 30 | (debug() && log({batchedQuery: query}, '')) || 31 | fetch( 32 | url, 33 | { 34 | method: 'POST', 35 | headers: { 36 | "Content-Type": 'application/json', 37 | "Authorization": `Bearer ${token}` 38 | }, 39 | body: JSON.stringify({ query, variables: args }) 40 | }) 41 | .then(r => r.json()) 42 | .then(f => { 43 | if(f.errors) throw new Error(f.errors.map(e => '\n- '+e.message).join('')) 44 | return f.data 45 | }) 46 | 47 | // register a free GraphQL endpoint at https://graph.cool 48 | const f = mux(fetcher('https://api.github.com/graphql'), 100) 49 | 50 | // want debug messages for parsing graphQL syntax? uncomment below 51 | debug(true) 52 | 53 | f(`($name: String!){ 54 | topic(name: $name) { 55 | name 56 | relatedTopics { 57 | id 58 | name 59 | } 60 | } 61 | }`, {name: 'typescript'}) 62 | .then(d => log(d, '')) 63 | 64 | f(`($name: String!){ 65 | topic(name: $name) { 66 | name 67 | relatedTopics { 68 | id 69 | name 70 | } 71 | } 72 | }`, {name: 'ruby'}) 73 | .then(d => log(d, '')) 74 | 75 | f(`($name: String!){ 76 | topic(name: $name) { 77 | name 78 | relatedTopics { 79 | id 80 | name 81 | } 82 | } 83 | }`, {name: 'ruby'}) 84 | .then(d => log(d, '')) 85 | 86 | f(`($name: String!){ 87 | topic(name: $name) { 88 | name 89 | relatedTopics { 90 | id 91 | name 92 | } 93 | } 94 | }`, {name: 'ruby'}) 95 | .then(d => log(d, '')) 96 | } 97 | 98 | require('batchql@1.1.14').then(app).catch(e => log(e)) 99 | ``` 100 | 101 | ## This is Dark Magic... 102 | 103 | Not really :-) For a given time-slice, one part of BatchQL's algorithm (the `mux()`) can take all calls for a given X ms and then send all of those query strings to the `batch()` method. 104 | 105 | The old method (BatchQL pre-1.0) used to take a best guess on batching the queries together by finding a general query statement and matching on parens or curly braces, but if the input query had invalid syntax then the algorithm kinda just blew up. 106 | 107 | It used to kinda do something like this: 108 | 109 | ```js 110 | const mergedQueries = batch('query { allPersons { name } }', 'query { allPersons { email } }', 'query { allPersons { age } }') 111 | mergedQueries 112 | // query { 113 | // item0: allPersons { name } 114 | // item1: allPersons { email } 115 | // item2: allPersons { age } 116 | // } 117 | ``` 118 | 119 | This merely batched the queries together, but didn't do an actual logical merge of the queries. But no more! Now we have an actual tree-merging batching mechanisms that doesn't batch _messages together_, it batches the _logical queries_. Yey! 120 | 121 | ```js 122 | const mergedQueries = batch('query { allPersons { name } }', 'query { allPersons { email } }', 'query { allPersons { age } }') 123 | mergedQueries 124 | // query { allPersons { name email age } } 125 | // sooooooooooooo much more efficient as queries get larger 126 | ``` 127 | 128 | How? 129 | 130 | Parsers, combinators, and parser-combinators. 131 | 132 | > Parser combinators propose a middle ground between hand-written parsers and generated parsers. They are made of small functions that handle basic parts of a format, like recognizing a word in ASCII characters or a null byte. Those functions are then composed in more useful building blocks like the pair combinator that applies two parsers in sequence, or the choice combinator that tries different parsers until one of them succeeds. 133 | 134 | > The functions are completely deterministic and hold no mutable state. The deterministic behaviour of parser combinators simplifies writing the state machine that manages data accumulation. 135 | 136 | We can actually parse GraphQL query strings into a lightweight Abstract Syntax Tree (AST), and then with multiple ASTs merge them into a single tree with some quick recursive logic. 137 | 138 | You can check out each piece in the various files under the `/src` folder. 139 | - `/src/parsers.ts` - code for parsing tokens 140 | - `/src/combinators.ts` - code for the parser combinators that contain the logic to parse entire GraphQL queries 141 | - `/src/merge.ts` - code for merging multiple ASTs into a single AST, generating extraction maps for parsing out the tree of data requested by each parallelized query, and logic for renaming query variables and aliases/query-fields that may have collisions (with built-in reverse maps) 142 | - `/src/regenerate.ts` - code for generating a GraphQL string from an AST 143 | - `/src/batchql.ts` - code for the muxer, a general fetcher, and the batch method, plus applying extraction maps to the returned data 144 | 145 | ## Embracing parser combinators 146 | 147 | > Changing the language is important, but it is not enough. Another component is required to help fix logical bugs, and make sure parsers are both easier to write and do not contain errors. 148 | 149 | Many low-level parsers ‘in the wild’ are written by hand, often because they need to deal with binary formats, or in a quest for better performance. Often these end up with hard to maintain code. At the other end of the spectrum there are parser generators, which tend to produce parsers of good quality but still present challenges in writing the grammar and integrating context specific libraries. 150 | 151 | In between these two choices lie parser combinators. 152 | 153 | > Parser combinators propose a middle ground between hand-written parsers and generated parsers. They are made of small functions that handle basic parts of a format, like recognizing a word in ASCII characters or a null byte. Those functions are then composed in more useful building blocks like the pair combinator that applies two parsers in sequence, or the choice combinator that tries different parsers until one of them succeeds. 154 | 155 | The functions are completely deterministic and hold no mutable state. The deterministic behaviour of parser combinators simplifies writing the state machine that manages data accumulation. 156 | 157 | - [Writing parsers like it is 2017](http://spw17.langsec.org/papers/chifflier-parsing-in-2017.pdf) Chifflier & Couprie, SPW’17 158 | 159 | ## Strengths of this approach 160 | 161 | If you choose to create "Service Oriented Components", meaning your components can request their own data (such as `onMount`), you run into sometimes 5 or 10 parallel graphql requests heading to your server: 162 | 163 | ``` 164 | 165 | +----------------------------+ 166 | | | 167 | | header | header -> `{ user { ...menuItems }}` 168 | | | 169 | | | 170 | | | 171 | +----------------------------+ 172 | | | 173 | | +-------------------------+ 174 | | | || || || || 175 | | | a || b || c || || a, b, c, d, e -> `{ content(id:???) { title, date, summary } } 176 | | | || || || || 177 | | +--------------------| || 178 | | +--------------------| e || 179 | | | || || 180 | | | || || 181 | | | d || || 182 | | | || || 183 | | | || || 184 | | +-------------------------| 185 | +----------------------------+ 186 | 187 | ``` 188 | 189 | With the 6 queries above it could take a lot longer to get the data you need to render to the screen quickly. 190 | 191 | BatchQL treats your queries like they are meant to be: logically independent (as much as I could do in a few days' time :D). So, using BatchQL is pretty straightforward and hopefully not too leaky of an abstraction: 192 | 193 | ```js 194 | // step 1. import batchql 195 | // mux :: (string -> object -> Promise) -> (string -> object -> Promise) 196 | import mux from 'batchql' 197 | 198 | // step 2. create your function the posts to your graphql endpoint 199 | const get = (url, query, args) => 200 | fetch( 201 | url 202 | , { 203 | method: 'POST' 204 | , headers: Object.assign( 205 | {'Content-Type': 'application/json'} 206 | , token ? {'authorization': `Bearer ${token}`} : {}) 207 | , body: JSON.stringify({ query, variables: args }) 208 | }) 209 | .then(r => r.json())) 210 | 211 | // step 3. batch it! 212 | const batchedGet = batchql(get.bind(null, 'https://mygraphqlendpoint.com/graphql')) 213 | 214 | // step 4. use it err'where? 215 | batchedGet(`{ user { id } }`).then(response => console.log(response.data.user)) 216 | batchedGet(`{ notifications { comments } }`).then(response => console.log(response.data.comments)) 217 | batchedGet(`{ messages { text, from } }`).then(response => console.log(response.data.messages)) 218 | ``` 219 | 220 | The end result of using batchql: 221 | 222 | ``` 223 | 224 | 225 | with batchql: 226 | 227 | 228 | 229 | +----------------------------+ 230 | | | 231 | | header | header +> `{ user { ...menuItems }}`+ 232 | | | | 233 | | | | 234 | | | | 235 | +----------------------------+ | 236 | | | | 237 | | +-------------------------+ | 238 | | | || || || || + 239 | | | a || b || c || || a, b, c, d, e +> `{ content(id:???) { title, date, summary } } 240 | | | || || || || +-------------------------------+ + 241 | | +--------------------| || | | | | | | 242 | | +--------------------| e || | | | | | | 243 | | | || || | | | | | | 244 | | | || || | | | | | | 245 | | | d || || | | | | | | 246 | | | || || | | | | | | 247 | | | || || | | | | | | 248 | | +-------------------------| | | | | | | 249 | +----------------------------+ +------v--v--v--v--v---v------------+ 250 | | | 251 | | batched querying | 252 | | | 253 | | | 254 | +-----------------------------------+ 255 | | 256 | SINGLE QUERY!! :D 257 | | 258 | XXXX|XX XXXXX 259 | XXXXXXXXXXX v XXX 260 | X X 261 | XXXX XX XXXXXX X 262 | XXX X 263 | X XX 264 | X graphql endpoint X 265 | X X 266 | X XX 267 | XXXXXXXXXXXXXXXXXX X 268 | XX XX 269 | XX XXXXXXX XX 270 | XXXXXXXXX XXXX XXX 271 | XXX 272 | 273 | ``` 274 | 275 | ## Caught a bug? 276 | 277 | 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device 278 | 2. Install the dependencies: `yarn` 279 | 3. Bundle the source code and watch for changes: `npm start` 280 | 281 | After that, you'll find the code in the `./build` folder! 282 | 283 | ## Authors 284 | 285 | - Matthew Keas, [@matthiasak](https://twitter.com/@matthiasak). Need help / support? Create an issue or ping on Twitter. 286 | 287 | ## Credits 288 | 289 | > Thanks to Amy Morgan on The Noun Project for the logo! -------------------------------------------------------------------------------- /build/batchql.d.ts: -------------------------------------------------------------------------------- 1 | import { debug } from './parsers'; 2 | export { debug }; 3 | export declare const batch: (...programs: any[]) => { 4 | mergedQuery: any; 5 | extractionMaps: any[]; 6 | queryVariableRenames: any; 7 | }; 8 | export declare const fetcher: (url: any) => (query: any, args: any) => Promise; 9 | export declare const mux: (getter: any, wait?: number) => (query: any, args: any) => any; 10 | export default mux; 11 | -------------------------------------------------------------------------------- /build/batchql.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var clan_fp_1 = require("clan-fp"); 4 | var merge_1 = require("./merge"); 5 | var regenerate_1 = require("./regenerate"); 6 | var combinators_1 = require("./combinators"); 7 | var parsers_1 = require("./parsers"); 8 | exports.debug = parsers_1.debug; 9 | exports.batch = function () { 10 | var programs = []; 11 | for (var _i = 0; _i < arguments.length; _i++) { 12 | programs[_i] = arguments[_i]; 13 | } 14 | var asts = programs.map(combinators_1["default"]), _a = merge_1["default"].apply(void 0, asts), mergedQuery = _a.mergedQuery, extractionMaps = _a.extractionMaps, queryVariableRenames = _a.queryVariableRenames; 15 | return { 16 | mergedQuery: regenerate_1["default"](mergedQuery), 17 | extractionMaps: extractionMaps, 18 | queryVariableRenames: queryVariableRenames 19 | }; 20 | }; 21 | exports.fetcher = function (url) { return function (query, args) { 22 | return (parsers_1.debug() && console.log(query)) || 23 | fetch(url, { 24 | method: 'POST', 25 | headers: { 26 | "Content-Type": 'application/json' 27 | }, 28 | body: JSON.stringify({ query: query, variables: args }) 29 | }) 30 | .then(function (r) { return r.json(); }) 31 | .then(function (f) { 32 | if (f.errors) 33 | throw new Error(f.errors.map(function (e) { return '\n- ' + e.message; }).join('')); 34 | return f.data; 35 | }); 36 | }; }; 37 | var appendOrClear = function (acc, x) { 38 | if (x === false) 39 | return []; 40 | acc.push(x); 41 | return acc; 42 | }; 43 | var applyQueryVarRenames = function (varMap, renameMap) { 44 | return Object 45 | .keys(varMap) 46 | .reduce(function (acc, key) { 47 | acc[key in renameMap ? renameMap[key] : key] = varMap[key]; 48 | return acc; 49 | }, {}); 50 | }; 51 | var applyExtractionMap = function (data, extractionMap) { 52 | if (data === null || data === undefined) 53 | return data; 54 | return Object 55 | .keys(extractionMap) 56 | .reduce(function (acc, key) { 57 | var _a = key.split('::'), actualKey = _a[0], renamedFrom = _a[1]; 58 | var dataTarget = data[actualKey]; 59 | if (dataTarget instanceof Array) { 60 | acc[renamedFrom || actualKey] = 61 | (extractionMap[key] === null || extractionMap[key] === undefined) ? 62 | dataTarget : 63 | dataTarget.map(function (item) { return applyExtractionMap(item, extractionMap[key]); }); 64 | } 65 | else if (dataTarget instanceof Object) { 66 | acc[renamedFrom || actualKey] = 67 | (extractionMap[key] === null || extractionMap[key] === undefined) ? 68 | data : 69 | applyExtractionMap(dataTarget, extractionMap[key]); 70 | } 71 | else if (dataTarget !== undefined) { 72 | acc[renamedFrom || actualKey] = dataTarget; 73 | } 74 | return acc; 75 | }, {}); 76 | }; 77 | exports.mux = function (getter, wait) { 78 | if (wait === void 0) { wait = 60; } 79 | var $queries = clan_fp_1.obs(), $callbacks = clan_fp_1.obs(), $data = clan_fp_1.obs(), responses = $callbacks.reduce(appendOrClear, []), payload = $queries.reduce(appendOrClear, []), append = function (_a) { 80 | var _b = _a.query, query = _b === void 0 ? '' : _b, _c = _a.args, args = _c === void 0 ? {} : _c; 81 | return $queries({ query: query, args: args }); 82 | }, send = clan_fp_1.obs(), queue = function (cb) { 83 | $callbacks(cb); 84 | send(true); 85 | }; 86 | send 87 | .debounce(wait) 88 | .then(function () { 89 | var data = payload(), $q = data.map(function (x) { return x.query; }), $a = data.map(function (x) { return x.args; }), $c = responses(); 90 | // clear 91 | $queries(false); 92 | $callbacks(false); 93 | var _a = exports.batch.apply(void 0, $q), mergedQuery = _a.mergedQuery, queryVariableRenames = _a.queryVariableRenames, extractionMaps = _a.extractionMaps, batchedArgs = $a.reduce(function (acc, x, i) { 94 | return Object.assign(acc, applyQueryVarRenames(x, queryVariableRenames[i])); 95 | }, {}); 96 | getter(mergedQuery, batchedArgs) 97 | .then(function (data) { 98 | return $c.map(function (fn, i) { 99 | return fn(applyExtractionMap(data, extractionMaps[i])); 100 | }); 101 | }); 102 | }); 103 | return function (query, args) { 104 | append({ query: query, args: args }); 105 | return new Promise(function (res) { return queue(function (d) { return res(d); }); }); 106 | }; 107 | }; 108 | exports["default"] = exports.mux; 109 | -------------------------------------------------------------------------------- /build/combinators.d.ts: -------------------------------------------------------------------------------- 1 | declare const parseProgram: (s: any) => any[]; 2 | export default parseProgram; 3 | -------------------------------------------------------------------------------- /build/combinators.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | ///////////////////////// 3 | // tokenizers 4 | ///////////////////////// 5 | exports.__esModule = true; 6 | var utils_1 = require("./utils"); 7 | var parsers_1 = require("./parsers"); 8 | var opType = parsers_1.either(parsers_1.token('query', 'opType'), parsers_1.token('mutation', 'opType'), parsers_1.token('subscription', 'opType')); 9 | var name = parsers_1.token(/^[_a-z][a-z0-9_]*/i, 'name'); //const name = token('\\w+', 'name') 10 | var alias = parsers_1.token(/^[_a-z][a-z0-9_]*/i, 'alias'); 11 | var variableName = parsers_1.token('\\$\\w+', 'variableName'); 12 | var scalarType = parsers_1.token(/^[\-_a-z]+\!?/i, 'type'); 13 | var typeClass = parsers_1.either(scalarType, parsers_1.sequence(parsers_1.token('\\['), scalarType, parsers_1.token('\\]'), parsers_1.maybe(parsers_1.token('\\!')))); 14 | var opArgListFn = parsers_1.sequence(parsers_1.ignore('\\('), parsers_1.readN(1, parsers_1.sequence(variableName, parsers_1.ignore(':'), typeClass, parsers_1.maybe(parsers_1.ignore(',')))), parsers_1.ignore('\\)')); 15 | var opArgList = function (s) { 16 | var v = opArgListFn(s); 17 | v.ast = { 18 | type: 'opArgList', 19 | value: utils_1.flatten(v.ast) 20 | .map(function (_a) { 21 | var a = _a[0], b = _a[1]; 22 | return ({ 23 | name: a.value, 24 | type: b instanceof Array ? 25 | b.map(function (_) { return _.value; }).join('') 26 | : b.value 27 | }); 28 | }) 29 | }; 30 | return v; 31 | }; 32 | var value = parsers_1.either(function (s) { 33 | var x = parsers_1.sequence(parsers_1.ignore('\\.{3}'), name)(s); 34 | x.ast = { value: x.ast[0].value, type: 'fragmentExpansion' }; 35 | return x; 36 | }, parsers_1.token(/^\d+(\.\d+)?/, 'number'), function (s) { 37 | var x = parsers_1.sequence(parsers_1.ignore('"'), parsers_1.token('[^"]*', 'string'), parsers_1.ignore('"'))(s); 38 | x.ast = x.ast[0]; 39 | return x; 40 | }, variableName, name); 41 | var filterArgFn = parsers_1.either(parsers_1.sequence(parsers_1.ignore('\\{'), parsers_1.readN(1, parsers_1.sequence(name, parsers_1.ignore(':'), function (s) { return filterArg(s); }, parsers_1.maybe(parsers_1.ignore(',')))), parsers_1.ignore('\\}')), value); 42 | var filterArg = function (s) { 43 | var v = filterArgFn(s); 44 | if (v.ast[0] instanceof Array) 45 | v.ast = utils_1.flatten(v.ast); 46 | return v; 47 | }; 48 | var selectionArgsFn = parsers_1.sequence(parsers_1.ignore('\\('), parsers_1.readN(0, parsers_1.sequence(name, parsers_1.ignore(':'), filterArg, parsers_1.maybe(parsers_1.ignore(',')))), parsers_1.ignore('\\)')); 49 | var selectionArgs = function (s) { 50 | var v = selectionArgsFn(s); 51 | var prep = function (_a) { 52 | var a = _a[0], b = _a[1]; 53 | return ({ 54 | type: 'arg', 55 | name: a.value, 56 | valueType: b instanceof Array ? 'arg' : b.type, 57 | value: b instanceof Array ? b.map(prep) : b.value 58 | }); 59 | }; 60 | v.ast = utils_1.flatten(v.ast).map(prep); 61 | return v; 62 | }; 63 | var fragmentExpansionFn = parsers_1.sequence(parsers_1.ignore(/^\.\.\./), name); 64 | var fragmentExpansion = function (s) { 65 | var v = fragmentExpansionFn(s); 66 | v.ast = { 67 | type: 'fragmentExpansion', 68 | value: v.ast[1].value 69 | }; 70 | return v; 71 | }; 72 | var intoSelection = function (arr) { 73 | if (!(arr instanceof Array)) { 74 | return arr; // not a subquery 75 | } 76 | var hasAlias = utils_1.first(arr, function (x) { return x.type === 'alias'; }), hasName = utils_1.first(arr, function (x) { return x.type === 'name'; }), numItems = [hasAlias, hasName] 77 | .reduce(function (acc, x) { return acc + (x && 1 || 0); }, 0), rest = arr.slice(numItems); 78 | return { 79 | alias: hasAlias && hasAlias.value, 80 | type: 'field', 81 | value: hasName && hasName.value, 82 | filterArgs: rest.length === 2 && rest[0], 83 | fields: rest[rest.length === 2 ? 1 : 0] 84 | }; 85 | }; 86 | var selectionSetFn = parsers_1.sequence(parsers_1.ignore('\\{'), parsers_1.readN(1, parsers_1.sequence(parsers_1.either(parsers_1.sequence(alias, parsers_1.ignore(':'), name, selectionArgs, function (s) { return selectionSet(s); }), parsers_1.sequence(alias, parsers_1.ignore(':'), name, function (s) { return selectionSet(s); }), parsers_1.sequence(name, selectionArgs, function (s) { return selectionSet(s); }), parsers_1.sequence(name, function (s) { return selectionSet(s); }), parsers_1.sequence(alias, parsers_1.ignore(':'), name), fragmentExpansion, name), parsers_1.maybe(parsers_1.ignore(',')))), parsers_1.ignore('\\}')); 87 | var selectionSet = function (s) { 88 | var v = selectionSetFn(s), parts = utils_1.flatten(utils_1.flatten(v.ast)); 89 | v.ast = { 90 | type: 'selectionSet', 91 | items: parts.map(intoSelection) 92 | }; 93 | return v; 94 | }; 95 | var statementFn = parsers_1.sequence(parsers_1.maybe(opType), parsers_1.maybe(name), parsers_1.maybe(opArgList), selectionSet); 96 | var statement = function (s) { 97 | var v = statementFn(s); 98 | var hasOptype = utils_1.first(v.ast, function (x, i) { return x.type === 'opType'; }), hasQueryName = utils_1.first(v.ast, function (x, i) { return x.type === 'name'; }), hasOpArgList = utils_1.first(v.ast, function (x, i) { return x.type === 'opArgList'; }), numItems = [hasOptype, hasQueryName, hasOpArgList] 99 | .reduce(function (acc, x) { return acc + (x && 1 || 0); }, 0); 100 | v.ast = { 101 | type: hasOptype && hasOptype.value || 'query', 102 | name: hasQueryName && hasQueryName.value || 'DEFAULTNAME', 103 | opArgList: hasOpArgList && hasOpArgList.value, 104 | children: v.ast.slice(numItems) 105 | }; 106 | return v; 107 | }; 108 | var fragmentFn = parsers_1.sequence(parsers_1.token('fragment'), name, parsers_1.ignore('on'), name, selectionSet); 109 | var fragment = function (s) { 110 | var v = fragmentFn(s); 111 | v.ast = { 112 | type: 'fragmentDefinition', 113 | name: v.ast[1].value, 114 | target: v.ast[2].value, 115 | children: v.ast[3] 116 | }; 117 | return v; 118 | }; 119 | var parseProgramFn = parsers_1.readN(1, parsers_1.either(statement, fragment)); 120 | var removeComments = function (s) { return s.replace(/#[^\n\r]*[\n\r]/igm, ''); }; 121 | var removeWhitespace = function (s) { return s.replace(/\s+/igm, ' '); }; 122 | var parseProgram = function (s) { 123 | var _a = parseProgramFn(removeWhitespace(removeComments(s))), remaining = _a.remaining, matched = _a.matched, ast = _a.ast; 124 | if (remaining !== '') 125 | throw new Error("remaining, unparsed snippet of graphQL query:\n\n" + remaining); 126 | return ast; 127 | }; 128 | exports["default"] = parseProgram; 129 | -------------------------------------------------------------------------------- /build/merge.d.ts: -------------------------------------------------------------------------------- 1 | declare const merge: (...asts: any[]) => { 2 | mergedQuery: any[]; 3 | queryVariableRenames: any; 4 | extractionMaps: any[]; 5 | }; 6 | export default merge; 7 | -------------------------------------------------------------------------------- /build/merge.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __assign = (this && this.__assign) || Object.assign || function(t) { 3 | for (var s, i = 1, n = arguments.length; i < n; i++) { 4 | s = arguments[i]; 5 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 6 | t[p] = s[p]; 7 | } 8 | return t; 9 | }; 10 | exports.__esModule = true; 11 | ////////////////////////////////// 12 | // query generation 13 | ////////////////////////////////// 14 | var utils_1 = require("./utils"); 15 | var findNameConflicts = function (query, _q) { 16 | if (_q === void 0) { _q = query || []; } 17 | return _q 18 | .reduce(function (acc, q, i) { 19 | (q.opArgList || []) 20 | .map(function (o) { return o.name.slice(1); }) 21 | .map(function (varName) { 22 | acc.counts[varName] = (acc.counts[varName] || 0) + 1; 23 | if (acc.counts[varName] > 1) { 24 | acc.renames[i][varName] = varName + "_" + i; 25 | } 26 | }); 27 | return acc; 28 | }, { 29 | counts: {}, 30 | renames: new Array(_q.length).fill(1).map(function (x) { return ({}); }) 31 | }) 32 | .renames; 33 | }; 34 | var applyVariableRenames = function (queries, varRenames) { 35 | if (varRenames === void 0) { varRenames = findNameConflicts(queries); } 36 | varRenames 37 | .map(function (renames, i) { 38 | var target = queries[i]; 39 | Object 40 | .keys(renames) 41 | .map(function (oldName) { 42 | var newName = renames[oldName]; 43 | applyOpArgListRenames(target.opArgList, oldName, newName); 44 | applySelectionSetRenames(((target.children || []) instanceof Array ? target.children : [target.children]) 45 | .filter(function (child) { return child.type === 'selectionSet' && child.items !== undefined; }) 46 | .reduce(function (acc, child) { return acc.concat(child.items); }, []), oldName, newName); 47 | }); 48 | }); 49 | return varRenames; 50 | }; 51 | var applyOpArgListRenames = function (opArgList, oldName, newName) { 52 | return (opArgList || []) 53 | .filter(function (arg) { return arg.name === '$' + oldName; }) 54 | .map(function (arg) { return arg.name = '$' + newName; }); 55 | }; 56 | var applySelectionSetRenames = function (children, oldName, newName) { 57 | return (children || []) 58 | .filter(function (field) { return field.type === 'field' && field.fields !== undefined; }) 59 | .map(function (field) { 60 | applyFilterArgListRenames(field.filterArgs || [], oldName, newName); 61 | applySelectionSetRenames(field.fields.items, oldName, newName); 62 | }); 63 | }; 64 | var applyFilterArgListRenames = function (filterArgList, oldName, newName) { 65 | filterArgList 66 | .filter(function (f) { return f.valueType === 'arg' && f.value !== undefined; }) 67 | .map(function (f) { return applyNestedArgRename(f, oldName, newName); }); 68 | filterArgList 69 | .filter(function (f) { return f.value === '$' + oldName; }) 70 | .map(function (f) { return f.value = '$' + newName; }); 71 | }; 72 | var applyNestedArgRename = function (nestedArg, oldName, newName) { 73 | if (nestedArg.value instanceof Array) { 74 | nestedArg 75 | .value 76 | .map(function (val) { return applyNestedArgRename(val, oldName, newName); }); 77 | } 78 | if (nestedArg.value === '$' + oldName) 79 | nestedArg.value = '$' + newName; 80 | }; 81 | /** 82 | * 1. build extraction map for first query 83 | * 2. build 2nd extraction map, looking at first map 84 | * 3. build 3rd extraction map, looking at first two maps 85 | * etc... 86 | */ 87 | var buildExtractionMap = function (fields, fieldsFromOtherQueries) { 88 | return fields 89 | .reduce(function (acc, f) { 90 | var key = f.alias || f.value, resultKey = key; 91 | var filterArgHash = utils_1.ohash(f.filterArgs); 92 | f.__visited = true; 93 | var similarlyNamedVisitedFieldsWithDiffFilterArgs = fields 94 | .concat(utils_1.flatten(fieldsFromOtherQueries)) 95 | .filter(function (f2) { 96 | return (f2.__visited === true) && 97 | (f2 !== f) && 98 | (f2.__oldKey || f2.alias || f2.value) === key && 99 | utils_1.ohash(f2.filterArgs) !== filterArgHash; 100 | }); 101 | if (similarlyNamedVisitedFieldsWithDiffFilterArgs.length >= 1) { 102 | f.alias = key + "_" + similarlyNamedVisitedFieldsWithDiffFilterArgs.length; 103 | f.__oldKey = key; 104 | resultKey = key + "_" + similarlyNamedVisitedFieldsWithDiffFilterArgs.length + "::" + key; 105 | } 106 | acc[resultKey] = 107 | (f.fields !== undefined) ? 108 | buildExtractionMap(f.fields.items, similarlyNamedVisitedFieldsWithDiffFilterArgs) : 109 | null; 110 | return acc; 111 | }, {}); 112 | }; 113 | var applyAliasingToCollidingFieldNames = function (queries) { 114 | if (queries === void 0) { queries = []; } 115 | return queries 116 | .map(function (q) { return q.children[0].items; }) 117 | .map(function (g, i, arr) { return buildExtractionMap(g, arr.slice(0, i)); }); 118 | }; 119 | // one function to bring them all and in the darkness bind them 120 | var merge = function () { 121 | var asts = []; 122 | for (var _i = 0; _i < arguments.length; _i++) { 123 | asts[_i] = arguments[_i]; 124 | } 125 | var entries = utils_1.flatten(asts), groupedOpsByType = utils_1.groupBy(entries, function (x) { return x.type; }); 126 | if (groupedOpsByType.mutation || groupedOpsByType.subscription) 127 | throw new Error("Mutations and Subscriptions currently not supported with BatchQL."); 128 | var queryVariableRenames = applyVariableRenames(entries), // cascade variable renames 129 | extractionMaps = applyAliasingToCollidingFieldNames(groupedOpsByType.query); 130 | var mergedQuery = (groupedOpsByType.query || []) 131 | .reduce(function (acc, q) { 132 | (_a = acc.opArgList).push.apply(_a, q.opArgList); 133 | (_b = acc.children).push.apply(_b, q.children); 134 | return acc; 135 | var _a, _b; 136 | }, { 137 | type: 'query', 138 | name: 'BATCHEDQUERY', 139 | opArgList: [], 140 | children: [] 141 | }); 142 | mergedQuery.children = 143 | utils_1.joinBy(utils_1.selectMany(mergedQuery.children, function (x) { return x.items; }), function (x) { return utils_1.only(x, 'alias', 'type', 'value', 'filterArgs'); }, function (items) { 144 | return utils_1.joinBy(utils_1.selectMany(items, function (x) { return x.fields.items; }), function (x) { return (__assign({}, x)); }); 145 | }, 'fields'); 146 | (groupedOpsByType.fragmentDefinition || []) 147 | .reduce(function (acc, fragment) { 148 | var key = fragment.name + '::' + fragment.target; 149 | if (acc[key] !== undefined) 150 | throw new Error("Multiple fragments named " + fragment.name + " defined on " + fragment.target); 151 | return __assign({}, acc, (_a = {}, _a[key] = 1, _a)); 152 | var _a; 153 | }, {}); 154 | return { 155 | mergedQuery: (groupedOpsByType.fragmentDefinition || []).concat(mergedQuery), 156 | queryVariableRenames: queryVariableRenames, 157 | extractionMaps: extractionMaps 158 | }; 159 | }; 160 | exports["default"] = merge; 161 | -------------------------------------------------------------------------------- /build/parsers.d.ts: -------------------------------------------------------------------------------- 1 | export declare const token: (t: any, type?: string, d?: number, o?: string, mod?: (x: any) => any) => (s: any) => any; 2 | export declare const debug: any; 3 | export declare const ignore: (...args: any[]) => any; 4 | export declare const interleave: (splitter: any, tokenizers: any) => any[]; 5 | export declare const sequence: (...tokenizers: any[]) => (s: any) => any; 6 | export declare const either: (...tokenizers: any[]) => (s: any) => any; 7 | export declare const maybe: (tokenizer: any) => (s: any) => any; 8 | export declare const readN: (n: any, tokenizer: any) => (s: any) => { 9 | remaining: any; 10 | matched: string; 11 | ast: any[]; 12 | }; 13 | -------------------------------------------------------------------------------- /build/parsers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | ///////////////////////// 3 | // Base functions / parsers + combinators 4 | ///////////////////////// 5 | var __assign = (this && this.__assign) || Object.assign || function(t) { 6 | for (var s, i = 1, n = arguments.length; i < n; i++) { 7 | s = arguments[i]; 8 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 9 | t[p] = s[p]; 10 | } 11 | return t; 12 | }; 13 | exports.__esModule = true; 14 | var clan_fp_1 = require("clan-fp"); 15 | // returns a function that takes a string which parses 16 | // the string according to a regexp or pattern, declaring the type of token 17 | exports.token = function (t, type, d, o, mod) { 18 | if (type === void 0) { type = t + ''; } 19 | if (d === void 0) { d = 0; } 20 | if (o === void 0) { o = 'igm'; } 21 | if (mod === void 0) { mod = function (x) { return x; }; } 22 | return function (s) { 23 | var r = t instanceof RegExp ? t : new RegExp('^' + t, o), results = r.exec(s); 24 | if (results === null || results.length <= d) 25 | throw new Error("expected: " + t + ", actual: " + s); 26 | return mod({ 27 | remaining: s.slice(results[d].length), 28 | matched: results[d], 29 | ast: { type: type, value: results[d] } 30 | }); 31 | }; 32 | }; 33 | exports.debug = clan_fp_1.obs(false); 34 | exports.ignore = function () { 35 | var args = []; 36 | for (var _i = 0; _i < arguments.length; _i++) { 37 | args[_i] = arguments[_i]; 38 | } 39 | var nArgs = args; 40 | nArgs[4] = function (x) { return (__assign({}, x, { ignore: true })); }; 41 | return exports.token.apply(void 0, nArgs); 42 | }; 43 | var ws = exports.ignore('\\s*'); 44 | var zip = function (a, b) { 45 | var result = []; 46 | for (var i = 0, len = Math.max(a.length, b.length); i < len; i++) { 47 | if (a[i]) 48 | result.push(a[i]); 49 | if (b[i]) 50 | result.push(b[i]); 51 | } 52 | return result; 53 | }; 54 | exports.interleave = function (splitter, tokenizers) { 55 | return zip(new Array(tokenizers.length + 1).fill(splitter), tokenizers); 56 | }; 57 | exports.sequence = function () { 58 | var tokenizers = []; 59 | for (var _i = 0; _i < arguments.length; _i++) { 60 | tokenizers[_i] = arguments[_i]; 61 | } 62 | return function (s) { 63 | return exports.interleave(ws, tokenizers) 64 | .reduce(function (acc, fn, i) { 65 | var _a = fn(acc.remaining), remaining = _a.remaining, matched = _a.matched, ast = _a.ast, ignore = _a.ignore; 66 | if (!ignore && ast) 67 | acc.ast.push(ast); 68 | acc.remaining = remaining; 69 | acc.matched += matched; 70 | return acc; 71 | }, { remaining: s, matched: '', ast: [] }); 72 | }; 73 | }; 74 | exports.either = function () { 75 | var tokenizers = []; 76 | for (var _i = 0; _i < arguments.length; _i++) { 77 | tokenizers[_i] = arguments[_i]; 78 | } 79 | return function (s) { 80 | var errors = []; 81 | for (var i = 0, len = tokenizers.length; i < len; i++) { 82 | try { 83 | return tokenizers[i](s); 84 | } 85 | catch (e) { 86 | errors.push(e.message); 87 | } 88 | } 89 | exports.debug() && console.warn(errors); 90 | throw new Error("Either failed."); 91 | }; 92 | }; 93 | exports.maybe = function (tokenizer) { return function (s) { 94 | try { 95 | return tokenizer(s); 96 | } 97 | catch (e) { 98 | return { remaining: s, matched: '', ast: null }; 99 | } 100 | }; }; 101 | exports.readN = function (n, tokenizer) { return function (s) { 102 | var acc = { remaining: s, matched: '', ast: [] }, current, count = 0, errors = []; 103 | try { 104 | while ((current = tokenizer(acc.remaining))) { 105 | var remaining = current.remaining, matched = current.matched, ast = current.ast, ignore_1 = current.ignore; 106 | if (remaining === acc.remaining) 107 | throw "Infinite loop detected in readN sequence."; 108 | if (!ignore_1 && ast) 109 | acc.ast.push(ast); 110 | acc.remaining = remaining; 111 | acc.matched += matched; 112 | count++; 113 | } 114 | } 115 | catch (e) { 116 | errors.push(e.message); 117 | } 118 | if (count < n) { 119 | exports.debug() && console.warn(errors); 120 | throw new Error("Expected " + n + "+ occurrences, but only have " + count + "."); 121 | } 122 | return acc; 123 | }; }; 124 | -------------------------------------------------------------------------------- /build/regenerate.d.ts: -------------------------------------------------------------------------------- 1 | declare const regenerate: (ast: any) => any; 2 | export default regenerate; 3 | -------------------------------------------------------------------------------- /build/regenerate.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var generateOpArgList = function (args) { 4 | if (!args || args.length === 0) 5 | return ''; 6 | return '(' + args.map(function (a) { return a.name + ": " + a.type; }).join(', ') + ')'; 7 | }; 8 | var generateValue = function (value, type) { 9 | if (type === undefined) 10 | return 'undefined'; 11 | if (type === null) 12 | return 'null'; 13 | if (type === 'number') 14 | return value; 15 | if (type === 'boolean') 16 | return value ? 'true' : 'false'; 17 | if (type === 'variableName') 18 | return value; 19 | if (type === 'arg') 20 | return '{' + 21 | value.map(function (v) { return v.name + ":" + generateValue(v.value, v.valueType); }).join(', ') + 22 | '}'; 23 | return "\"" + value + "\""; 24 | }; 25 | var generateFilterArgs = function (args) { 26 | if (!args || args.length === 0) 27 | return ''; 28 | return '(' + 29 | args 30 | .map(function (_a) { 31 | var name = _a.name, value = _a.value, valueType = _a.valueType; 32 | return name + ": " + generateValue(value, valueType); 33 | }) 34 | .join(', ') + 35 | ')'; 36 | }; 37 | var generateFields = function (args) { 38 | if (!args || args.length === 0) 39 | return ''; 40 | return '{' + 41 | args 42 | .map(function (x) { 43 | var type = x.type, value = x.value, filterArgs = x.filterArgs, fields = x.fields; 44 | if (type === 'field') 45 | return generateSelectionSet([x]); 46 | if (type === 'name') 47 | return value; 48 | }) 49 | .join(' ') + 50 | '}'; 51 | }; 52 | var generateSelectionSet = function (set) { 53 | if (!set || set.length === 0) 54 | return '{}'; 55 | return set 56 | .map(function (_a) { 57 | var value = _a.value, filterArgs = _a.filterArgs, fields = _a.fields, alias = _a.alias, items = _a.items; 58 | return (alias ? alias + " : " : '') + 59 | value + 60 | (items ? 61 | generateFields(items) : 62 | (generateFilterArgs(filterArgs) + 63 | generateFields(fields instanceof Array ? fields : (fields && fields.items)))); 64 | }) 65 | .join(' '); 66 | }; 67 | var generateQuery = function (_a) { 68 | var type = _a.type, name = _a.name, opArgList = _a.opArgList, children = _a.children; 69 | return type + " " + (name || '') + " " + generateOpArgList(opArgList) + " " + generateFields(children); 70 | }; 71 | var generateFragment = function (_a) { 72 | var name = _a.name, target = _a.target, child = _a.children; 73 | return "fragment " + name + " on " + target + " " + generateFields(child.items); 74 | }; 75 | var regenerate = function (ast) { 76 | return ast.reduce(function (acc, q) { 77 | switch (q.type) { 78 | case "query": return acc + generateQuery(q) + '\n'; 79 | case "fragmentDefinition": return acc + generateFragment(q) + '\n'; 80 | default: throw new Error("Unknown operation: \"" + q.type + "\""); 81 | } 82 | }, ''); 83 | }; 84 | exports["default"] = regenerate; 85 | -------------------------------------------------------------------------------- /build/utils.d.ts: -------------------------------------------------------------------------------- 1 | export declare const first: (arr: any, fn: any) => any; 2 | export declare const flatten: (arr: any) => any; 3 | export declare const groupBy: (arr: any, fn: any) => any; 4 | export declare const hash: (v: any, _v?: string) => number; 5 | export declare const ordered: (obj: any) => any; 6 | export declare const ohash: (obj: any) => number; 7 | export declare const selectMany: (arr: any, fn: any) => any; 8 | export declare const joinBy: (arr: any, rootProps?: (x: any) => any, mapGroupedChildren?: (x: any) => any, childrenKey?: string, hashProps?: (x: any) => any) => any[]; 9 | export declare const only: (obj: any, ...keys: any[]) => any; 10 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | ///////////////////////// 3 | // utilities 4 | ///////////////////////// 5 | var __assign = (this && this.__assign) || Object.assign || function(t) { 6 | for (var s, i = 1, n = arguments.length; i < n; i++) { 7 | s = arguments[i]; 8 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 9 | t[p] = s[p]; 10 | } 11 | return t; 12 | }; 13 | exports.__esModule = true; 14 | exports.first = function (arr, fn) { 15 | for (var i = 0, n = arr.length; i < n; i++) { 16 | if (fn(arr[i], i)) 17 | return arr[i]; 18 | } 19 | }; 20 | exports.flatten = function (arr) { 21 | return arr.reduce(function (acc, x) { 22 | return acc.concat(x instanceof Array ? x : [x]); 23 | }, []); 24 | }; 25 | exports.groupBy = function (arr, fn) { 26 | return arr.reduce(function (acc, x, i) { 27 | var key = fn(x, i); 28 | acc[key] = acc[key] !== undefined ? acc[key].concat(x) : [x]; 29 | return acc; 30 | }, {}); 31 | }; 32 | exports.hash = function (v, _v) { 33 | if (_v === void 0) { _v = v === undefined ? 'undefined' : JSON.stringify(v); } 34 | var hash = 0; 35 | for (var i = 0, len = _v.length; i < len; ++i) { 36 | var c = _v.charCodeAt(i); 37 | hash = (((hash << 5) - hash) + c) | 0; 38 | } 39 | return hash; 40 | }; 41 | exports.ordered = function (obj) { 42 | return Object 43 | .keys(obj) 44 | .sort() 45 | .reduce(function (acc, key) { 46 | return (__assign({}, acc, (_a = {}, _a[key] = obj[key] instanceof Object ? exports.ordered(obj[key]) : obj[key], _a))); 47 | var _a; 48 | }, {}); 49 | }; 50 | exports.ohash = function (obj) { return exports.hash(obj instanceof Object ? exports.ordered(obj) : {}); }; 51 | exports.selectMany = function (arr, fn) { 52 | return arr.reduce(function (acc, x) { return acc.concat(fn(x)); }, []); 53 | }; 54 | exports.joinBy = function (arr, rootProps, mapGroupedChildren, childrenKey, hashProps) { 55 | if (rootProps === void 0) { rootProps = function (x) { return x; }; } 56 | if (mapGroupedChildren === void 0) { mapGroupedChildren = function (x) { return undefined; }; } 57 | if (childrenKey === void 0) { childrenKey = 'children'; } 58 | if (hashProps === void 0) { hashProps = rootProps; } 59 | var g = exports.groupBy(arr, function (x) { return exports.ohash(hashProps(x)); }); 60 | return Object 61 | .keys(g) 62 | .reduce(function (acc, key) { 63 | var items = g[key], first = rootProps(items[0]), m = mapGroupedChildren(items); 64 | if (m !== undefined) 65 | first[childrenKey] = m; 66 | return acc.concat(first); 67 | }, []); 68 | }; 69 | exports.only = function (obj) { 70 | var keys = []; 71 | for (var _i = 1; _i < arguments.length; _i++) { 72 | keys[_i - 1] = arguments[_i]; 73 | } 74 | return keys.reduce(function (acc, key) { 75 | return (__assign({}, acc, (_a = {}, _a[key] = obj[key], _a))); 76 | var _a; 77 | }, {}); 78 | }; 79 | -------------------------------------------------------------------------------- /fuse.js: -------------------------------------------------------------------------------- 1 | const f = require("fuse-box") 2 | , { Sparky, FuseBox:fb } = f 3 | , path = require("path") 4 | 5 | Sparky.task("test", () => 6 | fb 7 | .init({homeDir: 'src', output: 'build/test.js'}) 8 | .bundle("app") 9 | .instructions('[*.ts]') 10 | .test("[**/**.test.ts]")) 11 | 12 | Sparky.task("default", ["clean"], () => { 13 | const build = fb.init({homeDir: 'src', output: 'build/$name.js', sourceMaps: true}) 14 | 15 | build 16 | .bundle('test') 17 | .instructions("> test.ts") 18 | .sourceMaps(true) 19 | .hmr() 20 | .watch() 21 | 22 | build 23 | .dev({ 24 | open: true, 25 | port: 4445 26 | }, server => { 27 | const p = path.resolve("./src/test.html") 28 | const app = server.httpServer.app 29 | app.get("/", (req, res) => { 30 | res.sendFile(p) 31 | }) 32 | }) 33 | 34 | build.run() 35 | }) 36 | 37 | Sparky.task("clean", () => Sparky.src("build/*").clean("build/").clean(".fusebox")) 38 | -------------------------------------------------------------------------------- /icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "batchql", 3 | "version": "1.1.18", 4 | "description": "Don't just graphql, batchql.", 5 | "scripts": { 6 | "prestart": "rimraf build/*", 7 | "start-old": "tsc -w src/batchql.ts --outDir build -d", 8 | "start": "node fuse.js", 9 | "prebuild": "rimraf build/*", 10 | "build": "NODE_ENV=production tsc src/batchql.ts --outDir build -d; echo \"done\";", 11 | "test": "node fuse.js test", 12 | "deploy": "npm run build; git commit -am \"snapshot\"; npm version patch; git push origin master; npm publish;" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git@github.com/matthiasak/clan" 17 | }, 18 | "keywords": [ 19 | "graphql", 20 | "mux", 21 | "multiplex" 22 | ], 23 | "main": "build/batchql.js", 24 | "author": "Matt Keas (@matthiasak)", 25 | "license": "MIT", 26 | "dependencies": { 27 | "clan-fp": "^1.1.40" 28 | }, 29 | "devDependencies": { 30 | "fuse-box": "^2.3.3", 31 | "fuse-test-runner": "^1.0.14", 32 | "rimraf": "^2.6.2", 33 | "typescript": "^2.8.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/batchql.test.ts: -------------------------------------------------------------------------------- 1 | 2 | // tests 3 | import {queries} from "./test-data" 4 | import { should } from "fuse-test-runner" 5 | import { batch, fetcher, mux } from "./batchql" 6 | import parseProgram from "./combinators" 7 | import regenerate from "./regenerate" 8 | 9 | export class Test { 10 | timeout: 5000; 11 | 12 | "should mux queries and args together"() { 13 | 14 | // echo back the query and args 15 | const mock = (query, args) => 16 | new Promise(res => 17 | setTimeout(() => res({query, args})), 0) 18 | 19 | const f = mux(mock) 20 | 21 | queries 22 | .map(q => 23 | should(f(q, {id: Math.random()})) 24 | .bePromise() 25 | .beOkay()) 26 | } 27 | } -------------------------------------------------------------------------------- /src/batchql.ts: -------------------------------------------------------------------------------- 1 | import {obs} from 'clan-fp' 2 | import merge from './merge' 3 | import regenerate from './regenerate' 4 | import parseProgram from './combinators' 5 | import {debug} from './parsers' 6 | 7 | export {debug} 8 | 9 | export const batch = (...programs) => { 10 | const asts = programs.map(parseProgram), 11 | { 12 | mergedQuery, 13 | extractionMaps, 14 | queryVariableRenames 15 | } = merge(...asts) 16 | 17 | return { 18 | mergedQuery: regenerate(mergedQuery), 19 | extractionMaps, 20 | queryVariableRenames 21 | } 22 | } 23 | 24 | export const fetcher = (url) => (query, args) => 25 | (debug() && console.log(query)) || 26 | fetch( 27 | url, 28 | { 29 | method: 'POST', 30 | headers: { 31 | "Content-Type": 'application/json' 32 | }, 33 | body: JSON.stringify({ query, variables: args }) 34 | }) 35 | .then(r => r.json()) 36 | .then(f => { 37 | if(f.errors) throw new Error(f.errors.map(e => '\n- '+e.message).join('')) 38 | return f.data 39 | }) 40 | 41 | const appendOrClear = (acc,x) => { 42 | if(x === false) return [] 43 | acc.push(x) 44 | return acc 45 | } 46 | 47 | const applyQueryVarRenames = (varMap, renameMap) => 48 | Object 49 | .keys(varMap) 50 | .reduce((acc,key) => { 51 | acc[key in renameMap ? renameMap[key] : key] = varMap[key] 52 | return acc 53 | }, {}) 54 | 55 | const applyExtractionMap = (data, extractionMap) => { 56 | if(data === null || data === undefined) return data 57 | 58 | return Object 59 | .keys(extractionMap) 60 | .reduce( 61 | (acc,key) => { 62 | const [actualKey, renamedFrom] = key.split('::') 63 | const dataTarget = data[actualKey] 64 | 65 | if(dataTarget instanceof Array){ 66 | acc[renamedFrom || actualKey] = 67 | (extractionMap[key] === null || extractionMap[key] === undefined) ? 68 | dataTarget : 69 | dataTarget.map(item => applyExtractionMap(item, extractionMap[key])) 70 | } else if(dataTarget instanceof Object){ 71 | acc[renamedFrom || actualKey] = 72 | (extractionMap[key] === null || extractionMap[key] === undefined) ? 73 | data : 74 | applyExtractionMap(dataTarget,extractionMap[key]) 75 | } else if(dataTarget !== undefined){ 76 | acc[renamedFrom || actualKey] = dataTarget 77 | } 78 | return acc 79 | }, 80 | {}) 81 | } 82 | 83 | export const mux = (getter, wait=60) => { 84 | const $queries = obs(), 85 | $callbacks = obs(), 86 | $data = obs(), 87 | responses = $callbacks.reduce(appendOrClear, []), 88 | payload = $queries.reduce(appendOrClear, []), 89 | append = ({ query='', args={} }) => $queries({query, args}), 90 | send = obs(), 91 | queue = cb => { 92 | $callbacks(cb) 93 | send(true) 94 | } 95 | 96 | send 97 | .debounce(wait) 98 | .then(() => { 99 | let data = payload(), 100 | $q = data.map(x => x.query), 101 | $a = data.map(x => x.args), 102 | $c = responses() 103 | 104 | // clear 105 | $queries(false) 106 | $callbacks(false) 107 | 108 | let {mergedQuery, queryVariableRenames, extractionMaps} = batch(...$q), 109 | batchedArgs = 110 | $a.reduce((acc, x, i) => 111 | Object.assign(acc, applyQueryVarRenames(x, queryVariableRenames[i])), 112 | {}) 113 | 114 | getter(mergedQuery, batchedArgs) 115 | .then(data => 116 | $c.map((fn, i) => 117 | fn(applyExtractionMap(data, extractionMaps[i])))) 118 | }) 119 | 120 | return (query, args) => { 121 | append({query, args}) 122 | return new Promise(res => queue(d => res(d))) 123 | } 124 | } 125 | 126 | export default mux -------------------------------------------------------------------------------- /src/combinators.ts: -------------------------------------------------------------------------------- 1 | ///////////////////////// 2 | // tokenizers 3 | ///////////////////////// 4 | 5 | import {flatten, first} from './utils' 6 | import {token, ignore, interleave, sequence, either, maybe, readN} from './parsers' 7 | 8 | const opType = either(token('query', 'opType'), token('mutation', 'opType'), token('subscription', 'opType')) 9 | const name = token(/^[_a-z][a-z0-9_]*/i, 'name') //const name = token('\\w+', 'name') 10 | const alias = token(/^[_a-z][a-z0-9_]*/i, 'alias') 11 | const variableName = token('\\$\\w+', 'variableName') 12 | const scalarType = token(/^[\-_a-z]+\!?/i, 'type') 13 | const typeClass = 14 | either( 15 | scalarType, 16 | sequence(token('\\['), scalarType, token('\\]'), maybe(token('\\!'))) 17 | ) 18 | 19 | const opArgListFn = 20 | sequence( 21 | ignore('\\('), 22 | readN( 23 | 1, 24 | sequence( 25 | variableName, 26 | ignore(':'), 27 | typeClass, 28 | maybe(ignore(',')) 29 | ) 30 | ), 31 | ignore('\\)') 32 | ) 33 | 34 | const opArgList = s => { 35 | let v = opArgListFn(s) 36 | 37 | v.ast = { 38 | type: 'opArgList', 39 | value: 40 | flatten(v.ast) 41 | .map(([a,b]) => 42 | ({ 43 | name: a.value, 44 | type: 45 | b instanceof Array ? 46 | b.map(_ => _.value).join('') 47 | : b.value 48 | })) 49 | } 50 | 51 | return v 52 | } 53 | 54 | const value = 55 | either( 56 | s => { 57 | let x = sequence(ignore('\\.{3}'), name)(s) 58 | x.ast = { value: x.ast[0].value, type: 'fragmentExpansion' } 59 | return x 60 | }, 61 | token(/^\d+(\.\d+)?/, 'number'), 62 | s => { 63 | let x = sequence(ignore('"'), token('[^"]*', 'string'), ignore('"'))(s) 64 | x.ast = x.ast[0] 65 | return x 66 | }, 67 | variableName, 68 | name 69 | ) 70 | 71 | const filterArgFn = 72 | either( 73 | sequence( 74 | ignore('\\{'), 75 | readN( 76 | 1, 77 | sequence( 78 | name, 79 | ignore(':'), 80 | s => filterArg(s), 81 | maybe(ignore(',')) 82 | ) 83 | ), 84 | ignore('\\}'), 85 | ), 86 | value 87 | ) 88 | 89 | const filterArg = s => { 90 | let v = filterArgFn(s) 91 | if(v.ast[0] instanceof Array) v.ast = flatten(v.ast) 92 | return v 93 | } 94 | 95 | const selectionArgsFn = 96 | sequence( 97 | ignore('\\('), 98 | readN(0, sequence(name, ignore(':'), filterArg, maybe(ignore(',')))), 99 | ignore('\\)') 100 | ) 101 | 102 | const selectionArgs = s => { 103 | let v = selectionArgsFn(s) 104 | 105 | const prep = ([a,b]) => 106 | ({ 107 | type: 'arg', 108 | name: a.value, 109 | valueType: b instanceof Array ? 'arg' : b.type, 110 | value: b instanceof Array ? b.map(prep) : b.value 111 | }) 112 | 113 | v.ast = flatten(v.ast).map(prep) 114 | 115 | return v 116 | } 117 | 118 | const fragmentExpansionFn = sequence(ignore(/^\.\.\./), name) 119 | const fragmentExpansion = s => { 120 | let v = fragmentExpansionFn(s) 121 | 122 | v.ast = { 123 | type: 'fragmentExpansion', 124 | value: v.ast[1].value 125 | } 126 | 127 | return v 128 | } 129 | 130 | const intoSelection = arr => { 131 | if(!(arr instanceof Array)){ 132 | return arr // not a subquery 133 | } 134 | 135 | let hasAlias = first(arr, x => x.type === 'alias'), 136 | hasName = first(arr, x => x.type === 'name'), 137 | numItems = 138 | [hasAlias, hasName] 139 | .reduce((acc,x) => acc + (x && 1 || 0), 0), 140 | rest = arr.slice(numItems) 141 | 142 | return { 143 | alias: hasAlias && hasAlias.value, 144 | type: 'field', 145 | value: hasName && hasName.value, 146 | filterArgs: rest.length === 2 && rest[0], 147 | fields: rest[rest.length === 2 ? 1 : 0] 148 | } 149 | } 150 | 151 | const selectionSetFn = 152 | sequence( 153 | ignore('\\{'), 154 | readN( 155 | 1, 156 | sequence( 157 | either( 158 | sequence(alias, ignore(':'), name, selectionArgs, s => selectionSet(s)), 159 | sequence(alias, ignore(':'), name, s => selectionSet(s)), 160 | sequence(name, selectionArgs, s => selectionSet(s)), 161 | sequence(name, s => selectionSet(s)), 162 | sequence(alias, ignore(':'), name), 163 | fragmentExpansion, 164 | name 165 | ), 166 | maybe(ignore(',')) 167 | ) 168 | ), 169 | ignore('\\}')) 170 | 171 | const selectionSet = s => { 172 | let v = selectionSetFn(s), 173 | parts = flatten(flatten(v.ast)) 174 | 175 | v.ast = { 176 | type: 'selectionSet', 177 | items: parts.map(intoSelection) 178 | } 179 | 180 | return v 181 | } 182 | 183 | const statementFn = sequence(maybe(opType), maybe(name), maybe(opArgList), selectionSet) 184 | 185 | const statement = s => { 186 | let v = statementFn(s) 187 | 188 | let hasOptype = first(v.ast, (x,i) => x.type === 'opType'), 189 | hasQueryName = first(v.ast, (x,i) => x.type === 'name'), 190 | hasOpArgList = first(v.ast, (x,i) => x.type === 'opArgList'), 191 | numItems = 192 | [hasOptype, hasQueryName, hasOpArgList] 193 | .reduce((acc,x) => acc + (x && 1 || 0), 0) 194 | 195 | v.ast = { 196 | type: hasOptype && hasOptype.value || 'query', 197 | name: hasQueryName && hasQueryName.value || 'DEFAULTNAME', 198 | opArgList: hasOpArgList && hasOpArgList.value, 199 | children: v.ast.slice(numItems) 200 | } 201 | 202 | return v 203 | } 204 | 205 | const fragmentFn = sequence(token('fragment'), name, ignore('on'), name, selectionSet) 206 | const fragment = s => { 207 | let v = fragmentFn(s) 208 | 209 | v.ast = { 210 | type: 'fragmentDefinition', 211 | name: v.ast[1].value, 212 | target: v.ast[2].value, 213 | children: v.ast[3] 214 | } 215 | 216 | return v 217 | } 218 | 219 | const parseProgramFn = readN(1, either(statement,fragment)) 220 | const removeComments = s => s.replace(/#[^\n\r]*[\n\r]/igm, '') 221 | const removeWhitespace = s => s.replace(/\s+/igm, ' ') 222 | const parseProgram = s => { 223 | let {remaining, matched, ast} = parseProgramFn(removeWhitespace(removeComments(s))) 224 | if(remaining !== '') 225 | throw new Error(`remaining, unparsed snippet of graphQL query:\n\n${remaining}`) 226 | return ast 227 | } 228 | 229 | export default parseProgram -------------------------------------------------------------------------------- /src/merge.test.ts: -------------------------------------------------------------------------------- 1 | 2 | // tests 3 | 4 | import {queries} from "./test-data" 5 | import { should } from "fuse-test-runner" 6 | import { batch, fetcher, mux } from "./batchql" 7 | import parseProgram from "./combinators" 8 | import regenerate from "./regenerate" 9 | 10 | export class Test { 11 | timeout: 5000; 12 | 13 | "shouldParsePrograms()"() { 14 | should(batch(...queries)) 15 | .beOkay() 16 | } 17 | 18 | "shouldBatchAndResolve()"() { 19 | // echo back the query and args 20 | const mock = (query, args) => new Promise((res, rej) => res({query, args})) 21 | const f = mux(mock, 0) 22 | 23 | queries 24 | .map(q => 25 | should(f(q, {id: Math.random()})) 26 | .bePromise() 27 | .beOkay()) 28 | 29 | } 30 | } -------------------------------------------------------------------------------- /src/merge.ts: -------------------------------------------------------------------------------- 1 | ////////////////////////////////// 2 | // query generation 3 | ////////////////////////////////// 4 | import {flatten, first, groupBy, joinBy, only, selectMany, ohash} from './utils' 5 | 6 | const findNameConflicts = (query, _q = query || []) => 7 | _q 8 | .reduce((acc,q,i) => { 9 | 10 | (q.opArgList || []) 11 | .map(o => o.name.slice(1)) 12 | .map(varName => { 13 | acc.counts[varName] = (acc.counts[varName] || 0) + 1 14 | if(acc.counts[varName] > 1){ 15 | acc.renames[i][varName] = `${varName}_${i}` 16 | } 17 | }) 18 | 19 | return acc 20 | }, { 21 | counts: {}, 22 | renames: new Array(_q.length).fill(1).map(x => ({})) 23 | }) 24 | .renames 25 | 26 | const applyVariableRenames = (queries, varRenames = findNameConflicts(queries)) => { 27 | varRenames 28 | .map((renames, i) => { 29 | const target = queries[i] 30 | 31 | Object 32 | .keys(renames) 33 | .map(oldName => { 34 | const newName = renames[oldName] 35 | applyOpArgListRenames(target.opArgList, oldName, newName) 36 | applySelectionSetRenames( 37 | ((target.children || []) instanceof Array ? target.children : [target.children]) 38 | .filter(child => child.type === 'selectionSet' && child.items !== undefined) 39 | .reduce((acc, child) => [...acc, ...child.items], []), 40 | oldName, 41 | newName 42 | ) 43 | }) 44 | }) 45 | 46 | return varRenames 47 | } 48 | 49 | const applyOpArgListRenames = (opArgList, oldName, newName) => 50 | (opArgList || []) 51 | .filter(arg => arg.name === '$'+oldName) 52 | .map(arg => arg.name = '$'+newName) 53 | 54 | const applySelectionSetRenames = (children, oldName, newName) => 55 | (children || []) 56 | .filter(field => field.type === 'field' && field.fields !== undefined) 57 | .map(field => { 58 | applyFilterArgListRenames(field.filterArgs || [], oldName, newName) 59 | applySelectionSetRenames(field.fields.items, oldName, newName) 60 | }) 61 | 62 | const applyFilterArgListRenames = (filterArgList, oldName, newName) => { 63 | filterArgList 64 | .filter(f => f.valueType === 'arg' && f.value !== undefined) 65 | .map(f => applyNestedArgRename(f, oldName, newName)) 66 | 67 | filterArgList 68 | .filter(f => f.value === '$'+oldName) 69 | .map(f => f.value = '$'+newName) 70 | } 71 | 72 | const applyNestedArgRename = (nestedArg, oldName, newName) => { 73 | if(nestedArg.value instanceof Array){ 74 | nestedArg 75 | .value 76 | .map(val => applyNestedArgRename(val, oldName, newName)) 77 | } 78 | 79 | if(nestedArg.value === '$'+oldName) nestedArg.value = '$'+newName 80 | } 81 | 82 | /** 83 | * 1. build extraction map for first query 84 | * 2. build 2nd extraction map, looking at first map 85 | * 3. build 3rd extraction map, looking at first two maps 86 | * etc... 87 | */ 88 | const buildExtractionMap = (fields, fieldsFromOtherQueries) => 89 | fields 90 | .reduce((acc, f) => { 91 | let key = f.alias || f.value, 92 | resultKey = key 93 | const filterArgHash = ohash(f.filterArgs) 94 | 95 | f.__visited = true 96 | 97 | const similarlyNamedVisitedFieldsWithDiffFilterArgs = 98 | fields 99 | .concat(flatten(fieldsFromOtherQueries)) 100 | .filter(f2 => 101 | (f2.__visited === true) && 102 | (f2 !== f) && 103 | (f2.__oldKey || f2.alias || f2.value) === key && 104 | ohash(f2.filterArgs) !== filterArgHash 105 | ) 106 | 107 | if(similarlyNamedVisitedFieldsWithDiffFilterArgs.length >= 1){ 108 | f.alias = `${key}_${similarlyNamedVisitedFieldsWithDiffFilterArgs.length}` 109 | f.__oldKey = key 110 | resultKey = `${key}_${similarlyNamedVisitedFieldsWithDiffFilterArgs.length}::${key}` 111 | } 112 | 113 | acc[resultKey] = 114 | (f.fields !== undefined) ? 115 | buildExtractionMap(f.fields.items, similarlyNamedVisitedFieldsWithDiffFilterArgs) : 116 | null 117 | 118 | return acc 119 | }, {}) 120 | 121 | const applyAliasingToCollidingFieldNames = (queries=[]) => 122 | queries 123 | .map(q => q.children[0].items) 124 | .map((g, i, arr) => buildExtractionMap(g, arr.slice(0,i))) 125 | 126 | // one function to bring them all and in the darkness bind them 127 | const merge = (...asts) => { 128 | let entries = flatten(asts), 129 | groupedOpsByType = groupBy(entries, x => x.type) 130 | 131 | if(groupedOpsByType.mutation || groupedOpsByType.subscription) 132 | throw new Error(`Mutations and Subscriptions currently not supported with BatchQL.`) 133 | 134 | let queryVariableRenames = applyVariableRenames(entries), // cascade variable renames 135 | extractionMaps = applyAliasingToCollidingFieldNames(groupedOpsByType.query) 136 | 137 | let mergedQuery = 138 | (groupedOpsByType.query || []) 139 | .reduce((acc,q) => { 140 | acc.opArgList.push(...q.opArgList) 141 | acc.children.push(...q.children) 142 | return acc 143 | }, { 144 | type: 'query', 145 | name: 'BATCHEDQUERY', 146 | opArgList: [], 147 | children: [] 148 | }) 149 | 150 | mergedQuery.children = 151 | joinBy( 152 | selectMany(mergedQuery.children, x => x.items), 153 | x => only(x, 'alias', 'type', 'value', 'filterArgs'), 154 | items => 155 | joinBy( 156 | selectMany(items, x => x.fields.items), 157 | x => ({...x}) 158 | ), 159 | 'fields') 160 | 161 | ;(groupedOpsByType.fragmentDefinition || []) 162 | .reduce((acc,fragment) => { 163 | let key = fragment.name+'::'+fragment.target 164 | if(acc[key] !== undefined) 165 | throw new Error(`Multiple fragments named ${fragment.name} defined on ${fragment.target}`) 166 | 167 | return {...acc, [key]: 1} 168 | }, {}) 169 | 170 | return { 171 | mergedQuery: [...(groupedOpsByType.fragmentDefinition || []), ...mergedQuery], 172 | queryVariableRenames, 173 | extractionMaps 174 | } 175 | } 176 | 177 | export default merge -------------------------------------------------------------------------------- /src/parsers.ts: -------------------------------------------------------------------------------- 1 | ///////////////////////// 2 | // Base functions / parsers + combinators 3 | ///////////////////////// 4 | 5 | import {obs} from 'clan-fp' 6 | 7 | // returns a function that takes a string which parses 8 | // the string according to a regexp or pattern, declaring the type of token 9 | export const token = (t, type=t+'', d=0, o='igm', mod=x=>x) => s => { 10 | let r = t instanceof RegExp ? t : new RegExp('^'+t, o), 11 | results = r.exec(s) 12 | 13 | if(results === null || results.length <= d) 14 | throw new Error(`expected: ${t}, actual: ${s}`)) 15 | 16 | return mod({ 17 | remaining: s.slice(results[d].length) 18 | , matched: results[d] 19 | , ast: {type: type, value: results[d]} 20 | }) 21 | } 22 | 23 | export const debug = obs(false) 24 | 25 | export const ignore = (...args) => { 26 | let nArgs = args 27 | nArgs[4] = x => ({...x, ignore: true}) 28 | return token(...nArgs) 29 | } 30 | 31 | const ws = ignore('\\s*') 32 | 33 | const zip = (a, b) => { 34 | let result = [] 35 | for(var i = 0, len = Math.max(a.length, b.length); i < len; i++){ 36 | if(a[i]) result.push(a[i]) 37 | if(b[i]) result.push(b[i]) 38 | } 39 | return result 40 | } 41 | 42 | export const interleave = (splitter, tokenizers) => 43 | zip(new Array(tokenizers.length + 1).fill(splitter), tokenizers) 44 | 45 | export const sequence = (...tokenizers) => s => 46 | interleave(ws, tokenizers) 47 | .reduce((acc, fn, i) => { 48 | let {remaining, matched, ast, ignore} = fn(acc.remaining) 49 | if(!ignore && ast) acc.ast.push(ast) 50 | acc.remaining = remaining 51 | acc.matched += matched 52 | return acc 53 | } 54 | , {remaining:s, matched:'', ast: []}) 55 | 56 | export const either = (...tokenizers) => s => { 57 | let errors = [] 58 | for(let i = 0, len = tokenizers.length; i s => { 70 | try { 71 | return tokenizer(s) 72 | } catch(e) { 73 | return {remaining: s, matched: '', ast: null} 74 | } 75 | } 76 | 77 | export const readN = (n, tokenizer) => s => { 78 | let acc = {remaining: s, matched: '', ast: []} 79 | , current 80 | , count = 0 81 | , errors = [] 82 | 83 | try { 84 | while((current = tokenizer(acc.remaining))){ 85 | let {remaining, matched, ast, ignore} = current 86 | if(remaining === acc.remaining) throw `Infinite loop detected in readN sequence.` 87 | if(!ignore && ast) acc.ast.push(ast) 88 | acc.remaining = remaining 89 | acc.matched += matched 90 | count++ 91 | } 92 | } catch(e) { 93 | errors.push(e.message) 94 | } 95 | 96 | if(count < n) { 97 | debug() && console.warn(errors) 98 | throw new Error(`Expected ${n}+ occurrences, but only have ${count}.`) 99 | } 100 | 101 | return acc 102 | } -------------------------------------------------------------------------------- /src/regenerate.ts: -------------------------------------------------------------------------------- 1 | ////////////////////////////////// 2 | // query generation 3 | ////////////////////////////////// 4 | import {flatten, first, groupBy, joinBy, only, selectMany} from './utils' 5 | 6 | const generateOpArgList = args => { 7 | if(!args || args.length === 0) return '' 8 | return '(' + args.map(a => `${a.name}: ${a.type}`).join(', ') + ')' 9 | } 10 | 11 | const generateValue = (value, type) => { 12 | if(type === undefined) return 'undefined' 13 | if(type === null) return 'null' 14 | if(type === 'number') return value 15 | if(type === 'boolean') return value ? 'true' : 'false' 16 | if(type === 'variableName') return value 17 | 18 | if(type === 'arg') 19 | return '{' + 20 | value.map(v => `${v.name}:${generateValue(v.value, v.valueType)}`).join(', ') + 21 | '}' 22 | 23 | return `"${value}"` 24 | } 25 | 26 | const generateFilterArgs = args => { 27 | if(!args || args.length === 0) return '' 28 | 29 | return '(' + 30 | args 31 | .map(({name, value, valueType}) => { 32 | return `${name}: ${generateValue(value, valueType)}` 33 | }) 34 | .join(', ') + 35 | ')' 36 | } 37 | 38 | const generateFields = args => { 39 | if(!args || args.length === 0) return '' 40 | 41 | return '{' + 42 | args 43 | .map(x => { 44 | let {type, value, filterArgs, fields} = x 45 | if(type === 'field') return generateSelectionSet([x]) 46 | if(type === 'name') return value 47 | }) 48 | .join(' ') + 49 | '}' 50 | } 51 | 52 | const generateSelectionSet = set => { 53 | if(!set || set.length === 0) return '{}' 54 | return set 55 | .map(({value, filterArgs, fields, alias, items}) => { 56 | return (alias ? `${alias} : ` : '') + 57 | value + 58 | ( 59 | items ? 60 | generateFields(items) : 61 | ( 62 | generateFilterArgs(filterArgs) + 63 | generateFields(fields instanceof Array ? fields : (fields && fields.items)) 64 | ) 65 | ) 66 | }) 67 | .join(' ') 68 | } 69 | 70 | const generateQuery = ({type, name, opArgList, children}) => 71 | `${type} ${name || ''} ${generateOpArgList(opArgList)} ${generateFields(children)}` 72 | 73 | const generateFragment = ({name, target, children:child}) => 74 | `fragment ${name} on ${target} ${generateFields(child.items)}` 75 | 76 | const regenerate = ast => 77 | ast.reduce((acc,q) => { 78 | switch(q.type) { 79 | case "query": return acc + generateQuery(q) + '\n'; 80 | case "fragmentDefinition": return acc + generateFragment(q) + '\n'; 81 | default: throw new Error(`Unknown operation: "${q.type}"`) 82 | } 83 | }, '') 84 | 85 | export default regenerate -------------------------------------------------------------------------------- /src/test-data.ts: -------------------------------------------------------------------------------- 1 | export const queries = [ 2 | `query Person($id: ID!){ 3 | person(id: $id){ 4 | name 5 | email 6 | createdAt 7 | updatedAt 8 | siblings { name } 9 | } 10 | notifications(id: $id){ 11 | summary 12 | createdAt 13 | text 14 | } 15 | }`, 16 | `query Person($id: ID!){ 17 | person(id: $id){ 18 | name 19 | email 20 | createdAt 21 | updatedAt 22 | parents 23 | details(id: $id, a: {name: { thing: $id}}){ 24 | stuff 25 | moreStuff 26 | } 27 | } 28 | }`, 29 | `query OtherQuery($id: ID!) { 30 | someField(uniqueIdentifier: $id){ 31 | name 32 | email 33 | createdAt 34 | updatedAt 35 | parents { 36 | name 37 | dob 38 | } 39 | } 40 | }` 41 | ] 42 | 43 | export const testdata = [ 44 | { 45 | person: { 46 | name: "Matty K", 47 | email: "nacho@bizn.es", 48 | createdAt: +new Date - 1000 * 60 * 60 * 24, 49 | updatedAt: +new Date, 50 | siblings: [ 51 | { name: "Jeremy" }, 52 | { name: "Ian" } 53 | ] 54 | }, 55 | notifications: [ 56 | {summary: "test", text: "test"}, 57 | {summary: "test", text: "test"}, 58 | {summary: "test", text: "test"} 59 | ] 60 | } 61 | ] -------------------------------------------------------------------------------- /src/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | const {mux, batch, fetcher, debug} = require('./batchql') 2 | debug(true) 3 | 4 | const f = mux( 5 | fetcher('https://api.graph.cool/simple/v1/FF'), 6 | 100 7 | ) 8 | const log = (...args) => console.log(...args) 9 | console.clear() 10 | 11 | // f(`query test ($id: ID!, $name: String!) { allFiles { name } }`) 12 | // .then(d => log(d)) 13 | 14 | // f(`{ 15 | // allFiles { name contentType } 16 | // allUsers { name id _ordersMeta { count }} 17 | // }`) 18 | // .then(d => log(d)) 19 | 20 | // f(`query test($x: [String!]!, $y: [ID!]){ 21 | // allUsers(filter: {name_in: $x, id_in: $y}) { 22 | // name 23 | // id 24 | // } 25 | // }`, {x: ["Matt"], y: [1] }) 26 | // .then(d => log(d)) 27 | 28 | const repeat = (f,n) => 29 | Array(n) 30 | .fill(true) 31 | .map(x => f()) 32 | 33 | repeat( 34 | () => 35 | f(`query getFile($url: String!){ allFiles(url: $url){ name contentType } }`) 36 | .then(d => log(d)), 37 | 3) -------------------------------------------------------------------------------- /src/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { should } from "fuse-test-runner"; 2 | import * as utils from "./utils"; 3 | 4 | export class Test { 5 | "flatten() should flatten an array of arrays"() { 6 | should( 7 | utils 8 | .flatten([[1,2,3], [4,5,6]]) 9 | ) 10 | .deepEqual([1,2,3,4,5,6]) 11 | } 12 | 13 | "first() finds the first value in a collection matching a predicate"() { 14 | const list = [{a: 1}, {a: 2}, {a: 3}] 15 | 16 | should( 17 | utils.first( 18 | list, 19 | x => x.a === 2 20 | ) 21 | ).deepEqual({a: 2}) 22 | } 23 | 24 | "groupBy()"() { 25 | const list = [{a: 1, b: 2}, {a: 1, b: 3}], 26 | groupedByA = utils.groupBy(list, x => x.a), 27 | groupedByB = utils.groupBy(list, x => x.b) 28 | 29 | should(groupedByA) 30 | .beObject() 31 | .deepEqual({ '1': [ { a: 1, b: 2 }, { a: 1, b: 3 } ] }) 32 | .mutate(x => Object.keys(x).length) 33 | .equal(1) 34 | 35 | should(groupedByB) 36 | .beObject() 37 | .deepEqual({ '2': [{a:1,b:2}], '3': [{a:1,b:3}]}) 38 | .mutate(x => Object.keys(x).length) 39 | .equal(2) 40 | } 41 | 42 | "hash() - should be sufficiently random and deterministic, but ordering of keys is important"() { 43 | should(utils.hash({})).equal(utils.hash({})) 44 | should(utils.hash([1,2,3])).equal(utils.hash([1,2,3])) 45 | should(utils.hash({a:1, b:2})).notEqual(utils.hash({b:2, a:1})) 46 | } 47 | 48 | "ohash() - ordered hash, orders all keys recursively"() { 49 | should(utils.ohash({a:1, b:2})).equal(utils.ohash({b:2, a:1})) 50 | } 51 | 52 | "selectMany()"() { 53 | should(utils.selectMany([[1,2,3], [4,5,6], [7,8,9]], x => x.map(y => y+1))) 54 | .deepEqual([2,3,4,5,6,7,8,9,10]) 55 | } 56 | 57 | "joinBy()"() { 58 | const test = 59 | utils.joinBy( 60 | [ 61 | {a:{c: [1,2,3]}, type: 'test'}, 62 | {a:{c: [4,5,6]}, type: 'test'} 63 | ], 64 | x => ({type: x.type}), 65 | xs => xs.reduce((acc,x) => acc.concat(x.a.c), []) 66 | ) 67 | 68 | should(test[0]).deepEqual({ type: 'test', children: [ 1, 2, 3, 4, 5, 6 ] }) 69 | } 70 | 71 | "only()"() { 72 | should(utils.only({a:1, b:2, c:3}, 'a', 'c')).deepEqual({a:1, c:3}) 73 | } 74 | } -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | ///////////////////////// 2 | // utilities 3 | ///////////////////////// 4 | 5 | export const first = (arr, fn) => { 6 | for(let i = 0, n = arr.length; i 12 | arr.reduce((acc, x) => 13 | acc.concat(x instanceof Array ? x : [x]), 14 | [] 15 | ) 16 | 17 | export const groupBy = (arr, fn) => 18 | arr.reduce((acc, x, i) => { 19 | let key = fn(x, i) 20 | acc[key] = acc[key] !== undefined ? acc[key].concat(x) : [x] 21 | return acc 22 | }, {}) 23 | 24 | export const hash = (v,_v= v === undefined ? 'undefined' : JSON.stringify(v)) => { 25 | let hash = 0 26 | for (let i = 0, len = _v.length; i < len; ++i) { 27 | const c = _v.charCodeAt(i) 28 | hash = (((hash << 5) - hash) + c) | 0 29 | } 30 | return hash 31 | } 32 | 33 | export const ordered = obj => 34 | Object 35 | .keys(obj) 36 | .sort() 37 | .reduce((acc,key) => ({ 38 | ...acc, 39 | [key]: obj[key] instanceof Object ? ordered(obj[key]) : obj[key] 40 | }), {}) 41 | 42 | export const ohash = obj => hash(obj instanceof Object ? ordered(obj) : {}) 43 | 44 | export const selectMany = (arr, fn) => 45 | arr.reduce((acc,x) => acc.concat(fn(x)), []) 46 | 47 | export const joinBy = ( 48 | arr, 49 | rootProps = x => x, 50 | mapGroupedChildren = x => undefined, 51 | childrenKey = 'children', 52 | hashProps = rootProps 53 | ) => { 54 | let g = groupBy(arr, x => ohash(hashProps(x))) 55 | return Object 56 | .keys(g) 57 | .reduce((acc,key) => { 58 | let items = g[key], 59 | first = rootProps(items[0]), 60 | m = mapGroupedChildren(items) 61 | 62 | if(m !== undefined) first[childrenKey] = m 63 | return acc.concat(first) 64 | }, []) 65 | } 66 | 67 | export const only = (obj, ...keys) => 68 | keys.reduce((acc,key) => ({...acc, [key]: obj[key]}), {}) 69 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | abbrev@1: 6 | version "1.1.0" 7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" 8 | 9 | accepts@~1.3.3: 10 | version "1.3.4" 11 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" 12 | dependencies: 13 | mime-types "~2.1.16" 14 | negotiator "0.6.1" 15 | 16 | acorn-jsx@^4.0.1: 17 | version "4.0.1" 18 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.0.1.tgz#ada5a01573727a237774ce625564d079ec9de12a" 19 | dependencies: 20 | acorn "^5.0.3" 21 | 22 | acorn@^5.0.3: 23 | version "5.1.1" 24 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75" 25 | 26 | acorn@^5.1.2: 27 | version "5.5.3" 28 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" 29 | 30 | ajax-request@^1.2.0: 31 | version "1.2.3" 32 | resolved "https://registry.yarnpkg.com/ajax-request/-/ajax-request-1.2.3.tgz#99fcbec1d6d2792f85fa949535332bd14f5f3790" 33 | dependencies: 34 | file-system "^2.1.1" 35 | utils-extend "^1.0.7" 36 | 37 | ajv@^4.9.1: 38 | version "4.11.8" 39 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" 40 | dependencies: 41 | co "^4.6.0" 42 | json-stable-stringify "^1.0.1" 43 | 44 | amdefine@>=0.0.4: 45 | version "1.0.1" 46 | resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" 47 | 48 | ansi-escapes@^1.1.0: 49 | version "1.4.0" 50 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" 51 | 52 | ansi-escapes@^2.0.0: 53 | version "2.0.0" 54 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-2.0.0.tgz#5bae52be424878dd9783e8910e3fc2922e83c81b" 55 | 56 | ansi-regex@^2.0.0, ansi-regex@^2.1.1: 57 | version "2.1.1" 58 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 59 | 60 | ansi-regex@^3.0.0: 61 | version "3.0.0" 62 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 63 | 64 | ansi-styles@^2.2.1: 65 | version "2.2.1" 66 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 67 | 68 | ansi-styles@^3.0.0, ansi-styles@^3.1.0: 69 | version "3.2.0" 70 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" 71 | dependencies: 72 | color-convert "^1.9.0" 73 | 74 | ansi@^0.3.1: 75 | version "0.3.1" 76 | resolved "https://registry.yarnpkg.com/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" 77 | 78 | anymatch@^1.3.0: 79 | version "1.3.2" 80 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" 81 | dependencies: 82 | micromatch "^2.1.5" 83 | normalize-path "^2.0.0" 84 | 85 | app-root-path@^1.3.0: 86 | version "1.4.0" 87 | resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-1.4.0.tgz#6335d865c9640d0fad99004e5a79232238e92dfa" 88 | 89 | app-root-path@^2.0.1: 90 | version "2.0.1" 91 | resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46" 92 | 93 | aproba@^1.0.3: 94 | version "1.1.2" 95 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" 96 | 97 | are-we-there-yet@~1.1.2: 98 | version "1.1.4" 99 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" 100 | dependencies: 101 | delegates "^1.0.0" 102 | readable-stream "^2.0.6" 103 | 104 | arr-diff@^2.0.0: 105 | version "2.0.0" 106 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" 107 | dependencies: 108 | arr-flatten "^1.0.1" 109 | 110 | arr-flatten@^1.0.1: 111 | version "1.1.0" 112 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" 113 | 114 | array-flatten@1.1.1: 115 | version "1.1.1" 116 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 117 | 118 | array-unique@^0.2.1: 119 | version "0.2.1" 120 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" 121 | 122 | asn1@~0.2.3: 123 | version "0.2.3" 124 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" 125 | 126 | assert-plus@1.0.0, assert-plus@^1.0.0: 127 | version "1.0.0" 128 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 129 | 130 | assert-plus@^0.2.0: 131 | version "0.2.0" 132 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" 133 | 134 | async-each@^1.0.0: 135 | version "1.0.1" 136 | resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" 137 | 138 | asynckit@^0.4.0: 139 | version "0.4.0" 140 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 141 | 142 | aws-sign2@~0.6.0: 143 | version "0.6.0" 144 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" 145 | 146 | aws4@^1.2.1: 147 | version "1.6.0" 148 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" 149 | 150 | babel-polyfill@6.23.0: 151 | version "6.23.0" 152 | resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" 153 | dependencies: 154 | babel-runtime "^6.22.0" 155 | core-js "^2.4.0" 156 | regenerator-runtime "^0.10.0" 157 | 158 | babel-runtime@^6.22.0: 159 | version "6.26.0" 160 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" 161 | dependencies: 162 | core-js "^2.4.0" 163 | regenerator-runtime "^0.11.0" 164 | 165 | balanced-match@^0.4.1: 166 | version "0.4.2" 167 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 168 | 169 | balanced-match@^1.0.0: 170 | version "1.0.0" 171 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 172 | 173 | base64-img@^1.0.3: 174 | version "1.0.3" 175 | resolved "https://registry.yarnpkg.com/base64-img/-/base64-img-1.0.3.tgz#a8c0284900047103421e1f9e0214011333866806" 176 | dependencies: 177 | ajax-request "^1.2.0" 178 | file-system "^2.1.0" 179 | 180 | base64-js@^1.2.0: 181 | version "1.2.1" 182 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" 183 | 184 | bcrypt-pbkdf@^1.0.0: 185 | version "1.0.1" 186 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" 187 | dependencies: 188 | tweetnacl "^0.14.3" 189 | 190 | binary-extensions@^1.0.0: 191 | version "1.10.0" 192 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" 193 | 194 | block-stream@*: 195 | version "0.0.9" 196 | resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" 197 | dependencies: 198 | inherits "~2.0.0" 199 | 200 | boom@2.x.x: 201 | version "2.10.1" 202 | resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" 203 | dependencies: 204 | hoek "2.x.x" 205 | 206 | brace-expansion@^1.0.0: 207 | version "1.1.6" 208 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" 209 | dependencies: 210 | balanced-match "^0.4.1" 211 | concat-map "0.0.1" 212 | 213 | brace-expansion@^1.1.7: 214 | version "1.1.8" 215 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" 216 | dependencies: 217 | balanced-match "^1.0.0" 218 | concat-map "0.0.1" 219 | 220 | braces@^1.8.2: 221 | version "1.8.5" 222 | resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" 223 | dependencies: 224 | expand-range "^1.8.1" 225 | preserve "^0.2.0" 226 | repeat-element "^1.1.2" 227 | 228 | builtin-modules@^1.0.0: 229 | version "1.1.1" 230 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 231 | 232 | camelcase@^4.1.0: 233 | version "4.1.0" 234 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" 235 | 236 | caseless@~0.12.0: 237 | version "0.12.0" 238 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 239 | 240 | chain-able@^1.0.1: 241 | version "1.0.1" 242 | resolved "https://registry.yarnpkg.com/chain-able/-/chain-able-1.0.1.tgz#b48ac9bdc18f2192ec730abc66609f90aab5605f" 243 | 244 | chain-able@^3.0.0: 245 | version "3.0.0" 246 | resolved "https://registry.yarnpkg.com/chain-able/-/chain-able-3.0.0.tgz#dcffe8b04f3da210941a23843bc1332bb288ca9f" 247 | 248 | chalk@1.1.3, chalk@^1.0.0: 249 | version "1.1.3" 250 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 251 | dependencies: 252 | ansi-styles "^2.2.1" 253 | escape-string-regexp "^1.0.2" 254 | has-ansi "^2.0.0" 255 | strip-ansi "^3.0.0" 256 | supports-color "^2.0.0" 257 | 258 | chalk@^2.0.0, chalk@^2.1.0: 259 | version "2.1.0" 260 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" 261 | dependencies: 262 | ansi-styles "^3.1.0" 263 | escape-string-regexp "^1.0.5" 264 | supports-color "^4.0.0" 265 | 266 | chokidar@^1.6.1: 267 | version "1.7.0" 268 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" 269 | dependencies: 270 | anymatch "^1.3.0" 271 | async-each "^1.0.0" 272 | glob-parent "^2.0.0" 273 | inherits "^2.0.1" 274 | is-binary-path "^1.0.0" 275 | is-glob "^2.0.0" 276 | path-is-absolute "^1.0.0" 277 | readdirp "^2.0.0" 278 | optionalDependencies: 279 | fsevents "^1.0.0" 280 | 281 | clan-fp@^1.1.40: 282 | version "1.1.40" 283 | resolved "https://registry.yarnpkg.com/clan-fp/-/clan-fp-1.1.40.tgz#25483ba8d7a8d4f4f64394916ca32a33312354f1" 284 | dependencies: 285 | etag "^1.8.0" 286 | 287 | cli-cursor@^2.1.0: 288 | version "2.1.0" 289 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" 290 | dependencies: 291 | restore-cursor "^2.0.0" 292 | 293 | cli-width@^2.0.0: 294 | version "2.2.0" 295 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" 296 | 297 | cliui@^3.2.0: 298 | version "3.2.0" 299 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" 300 | dependencies: 301 | string-width "^1.0.1" 302 | strip-ansi "^3.0.1" 303 | wrap-ansi "^2.0.0" 304 | 305 | co@^4.6.0: 306 | version "4.6.0" 307 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 308 | 309 | code-point-at@^1.0.0: 310 | version "1.1.0" 311 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 312 | 313 | color-convert@^1.9.0: 314 | version "1.9.0" 315 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" 316 | dependencies: 317 | color-name "^1.1.1" 318 | 319 | color-name@^1.1.1: 320 | version "1.1.3" 321 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 322 | 323 | colors@^1.1.2: 324 | version "1.1.2" 325 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" 326 | 327 | combined-stream@^1.0.5, combined-stream@~1.0.5: 328 | version "1.0.5" 329 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" 330 | dependencies: 331 | delayed-stream "~1.0.0" 332 | 333 | concat-map@0.0.1: 334 | version "0.0.1" 335 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 336 | 337 | concat-with-sourcemaps@^1.0.4: 338 | version "1.0.4" 339 | resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz#f55b3be2aeb47601b10a2d5259ccfb70fd2f1dd6" 340 | dependencies: 341 | source-map "^0.5.1" 342 | 343 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 344 | version "1.1.0" 345 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 346 | 347 | content-disposition@0.5.2: 348 | version "0.5.2" 349 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 350 | 351 | content-type@~1.0.2: 352 | version "1.0.2" 353 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" 354 | 355 | cookie-signature@1.0.6: 356 | version "1.0.6" 357 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 358 | 359 | cookie@0.3.1: 360 | version "0.3.1" 361 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 362 | 363 | core-js@^2.4.0: 364 | version "2.5.0" 365 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.0.tgz#569c050918be6486b3837552028ae0466b717086" 366 | 367 | core-util-is@1.0.2, core-util-is@~1.0.0: 368 | version "1.0.2" 369 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 370 | 371 | cross-spawn@^5.0.1: 372 | version "5.1.0" 373 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" 374 | dependencies: 375 | lru-cache "^4.0.1" 376 | shebang-command "^1.2.0" 377 | which "^1.2.9" 378 | 379 | cryptiles@2.x.x: 380 | version "2.0.5" 381 | resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" 382 | dependencies: 383 | boom "2.x.x" 384 | 385 | dashdash@^1.12.0: 386 | version "1.14.1" 387 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 388 | dependencies: 389 | assert-plus "^1.0.0" 390 | 391 | debug@2.6.8, debug@^2.2.0: 392 | version "2.6.8" 393 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 394 | dependencies: 395 | ms "2.0.0" 396 | 397 | decamelize@^1.1.1: 398 | version "1.2.0" 399 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 400 | 401 | deep-extend@~0.4.0: 402 | version "0.4.2" 403 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" 404 | 405 | deep-is@~0.1.3: 406 | version "0.1.3" 407 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 408 | 409 | delayed-stream@~1.0.0: 410 | version "1.0.0" 411 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 412 | 413 | delegates@^1.0.0: 414 | version "1.0.0" 415 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 416 | 417 | depd@1.1.1, depd@~1.1.1: 418 | version "1.1.1" 419 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" 420 | 421 | destroy@~1.0.4: 422 | version "1.0.4" 423 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 424 | 425 | diff@^3.3.0: 426 | version "3.3.1" 427 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" 428 | 429 | ecc-jsbn@~0.1.1: 430 | version "0.1.1" 431 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" 432 | dependencies: 433 | jsbn "~0.1.0" 434 | 435 | ee-first@1.1.1: 436 | version "1.1.1" 437 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 438 | 439 | encodeurl@~1.0.1: 440 | version "1.0.1" 441 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" 442 | 443 | encoding@^0.1.11: 444 | version "0.1.12" 445 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 446 | dependencies: 447 | iconv-lite "~0.4.13" 448 | 449 | error-ex@^1.2.0: 450 | version "1.3.1" 451 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" 452 | dependencies: 453 | is-arrayish "^0.2.1" 454 | 455 | escape-html@~1.0.3: 456 | version "1.0.3" 457 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 458 | 459 | escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: 460 | version "1.0.5" 461 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 462 | 463 | escodegen@^1.8.1: 464 | version "1.8.1" 465 | resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" 466 | dependencies: 467 | esprima "^2.7.1" 468 | estraverse "^1.9.1" 469 | esutils "^2.0.2" 470 | optionator "^0.8.1" 471 | optionalDependencies: 472 | source-map "~0.2.0" 473 | 474 | esprima@^2.7.1: 475 | version "2.7.3" 476 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 477 | 478 | estraverse@^1.9.1: 479 | version "1.9.3" 480 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" 481 | 482 | esutils@^2.0.2: 483 | version "2.0.2" 484 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 485 | 486 | etag@^1.8.0, etag@~1.8.0: 487 | version "1.8.0" 488 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" 489 | 490 | exec-sh@^0.2.0: 491 | version "0.2.0" 492 | resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" 493 | dependencies: 494 | merge "^1.1.3" 495 | 496 | execa@^0.7.0: 497 | version "0.7.0" 498 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" 499 | dependencies: 500 | cross-spawn "^5.0.1" 501 | get-stream "^3.0.0" 502 | is-stream "^1.1.0" 503 | npm-run-path "^2.0.0" 504 | p-finally "^1.0.0" 505 | signal-exit "^3.0.0" 506 | strip-eof "^1.0.0" 507 | 508 | expand-brackets@^0.1.4: 509 | version "0.1.5" 510 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" 511 | dependencies: 512 | is-posix-bracket "^0.1.0" 513 | 514 | expand-range@^1.8.1: 515 | version "1.8.2" 516 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 517 | dependencies: 518 | fill-range "^2.1.0" 519 | 520 | express@^4.14.0: 521 | version "4.15.4" 522 | resolved "https://registry.yarnpkg.com/express/-/express-4.15.4.tgz#032e2253489cf8fce02666beca3d11ed7a2daed1" 523 | dependencies: 524 | accepts "~1.3.3" 525 | array-flatten "1.1.1" 526 | content-disposition "0.5.2" 527 | content-type "~1.0.2" 528 | cookie "0.3.1" 529 | cookie-signature "1.0.6" 530 | debug "2.6.8" 531 | depd "~1.1.1" 532 | encodeurl "~1.0.1" 533 | escape-html "~1.0.3" 534 | etag "~1.8.0" 535 | finalhandler "~1.0.4" 536 | fresh "0.5.0" 537 | merge-descriptors "1.0.1" 538 | methods "~1.1.2" 539 | on-finished "~2.3.0" 540 | parseurl "~1.3.1" 541 | path-to-regexp "0.1.7" 542 | proxy-addr "~1.1.5" 543 | qs "6.5.0" 544 | range-parser "~1.2.0" 545 | send "0.15.4" 546 | serve-static "1.12.4" 547 | setprototypeof "1.0.3" 548 | statuses "~1.3.1" 549 | type-is "~1.6.15" 550 | utils-merge "1.0.0" 551 | vary "~1.1.1" 552 | 553 | extend@~3.0.0: 554 | version "3.0.1" 555 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" 556 | 557 | external-editor@^2.0.1, external-editor@^2.0.4: 558 | version "2.0.4" 559 | resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972" 560 | dependencies: 561 | iconv-lite "^0.4.17" 562 | jschardet "^1.4.2" 563 | tmp "^0.0.31" 564 | 565 | extglob@^0.3.1: 566 | version "0.3.2" 567 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" 568 | dependencies: 569 | is-extglob "^1.0.0" 570 | 571 | extsprintf@1.3.0, extsprintf@^1.2.0: 572 | version "1.3.0" 573 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 574 | 575 | fast-levenshtein@~2.0.4: 576 | version "2.0.6" 577 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 578 | 579 | figures@^2.0.0: 580 | version "2.0.0" 581 | resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" 582 | dependencies: 583 | escape-string-regexp "^1.0.5" 584 | 585 | file-match@^1.0.1: 586 | version "1.0.2" 587 | resolved "https://registry.yarnpkg.com/file-match/-/file-match-1.0.2.tgz#c9cad265d2c8adf3a81475b0df475859069faef7" 588 | dependencies: 589 | utils-extend "^1.0.6" 590 | 591 | file-system@^2.1.0, file-system@^2.1.1: 592 | version "2.2.2" 593 | resolved "https://registry.yarnpkg.com/file-system/-/file-system-2.2.2.tgz#7d65833e3a2347dcd956a813c677153ed3edd987" 594 | dependencies: 595 | file-match "^1.0.1" 596 | utils-extend "^1.0.4" 597 | 598 | filename-regex@^2.0.0: 599 | version "2.0.1" 600 | resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" 601 | 602 | fill-range@^2.1.0: 603 | version "2.2.3" 604 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" 605 | dependencies: 606 | is-number "^2.1.0" 607 | isobject "^2.0.0" 608 | randomatic "^1.1.3" 609 | repeat-element "^1.1.2" 610 | repeat-string "^1.5.2" 611 | 612 | finalhandler@~1.0.4: 613 | version "1.0.4" 614 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.4.tgz#18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7" 615 | dependencies: 616 | debug "2.6.8" 617 | encodeurl "~1.0.1" 618 | escape-html "~1.0.3" 619 | on-finished "~2.3.0" 620 | parseurl "~1.3.1" 621 | statuses "~1.3.1" 622 | unpipe "~1.0.0" 623 | 624 | find-up@^2.0.0: 625 | version "2.1.0" 626 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" 627 | dependencies: 628 | locate-path "^2.0.0" 629 | 630 | fliplog@^0.3.13: 631 | version "0.3.13" 632 | resolved "https://registry.yarnpkg.com/fliplog/-/fliplog-0.3.13.tgz#dd0d786e821822aae272e0ddc84012596a96154c" 633 | dependencies: 634 | chain-able "^1.0.1" 635 | 636 | for-in@^1.0.1: 637 | version "1.0.2" 638 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 639 | 640 | for-own@^0.1.4: 641 | version "0.1.5" 642 | resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" 643 | dependencies: 644 | for-in "^1.0.1" 645 | 646 | forever-agent@~0.6.1: 647 | version "0.6.1" 648 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 649 | 650 | form-data@~2.1.1: 651 | version "2.1.4" 652 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" 653 | dependencies: 654 | asynckit "^0.4.0" 655 | combined-stream "^1.0.5" 656 | mime-types "^2.1.12" 657 | 658 | forwarded@~0.1.0: 659 | version "0.1.0" 660 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" 661 | 662 | fresh@0.5.0: 663 | version "0.5.0" 664 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" 665 | 666 | fs-extra@^2.0.0: 667 | version "2.1.2" 668 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" 669 | dependencies: 670 | graceful-fs "^4.1.2" 671 | jsonfile "^2.1.0" 672 | 673 | fs.realpath@^1.0.0: 674 | version "1.0.0" 675 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 676 | 677 | fsevents@^1.0.0: 678 | version "1.1.2" 679 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" 680 | dependencies: 681 | nan "^2.3.0" 682 | node-pre-gyp "^0.6.36" 683 | 684 | fstream-ignore@^1.0.5: 685 | version "1.0.5" 686 | resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" 687 | dependencies: 688 | fstream "^1.0.0" 689 | inherits "2" 690 | minimatch "^3.0.0" 691 | 692 | fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: 693 | version "1.0.11" 694 | resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" 695 | dependencies: 696 | graceful-fs "^4.1.2" 697 | inherits "~2.0.0" 698 | mkdirp ">=0.5 0" 699 | rimraf "2" 700 | 701 | fuse-box@^2.3.3: 702 | version "2.4.0" 703 | resolved "https://registry.yarnpkg.com/fuse-box/-/fuse-box-2.4.0.tgz#da0d0752d7a22f83fda8222e717b329fe823f910" 704 | dependencies: 705 | acorn "^5.1.2" 706 | acorn-jsx "^4.0.1" 707 | ansi "^0.3.1" 708 | app-root-path "^2.0.1" 709 | base64-img "^1.0.3" 710 | base64-js "^1.2.0" 711 | chokidar "^1.6.1" 712 | concat-with-sourcemaps "^1.0.4" 713 | escodegen "^1.8.1" 714 | express "^4.14.0" 715 | fliplog "^0.3.13" 716 | fs-extra "^2.0.0" 717 | fuse-tools "^1.0.4" 718 | glob "^7.1.1" 719 | ieee754 "^1.1.8" 720 | inquirer "^3.0.6" 721 | lego-api "^1.0.7" 722 | mustache "^2.3.0" 723 | opencollective "^1.0.3" 724 | postcss "^6.0.1" 725 | pretty-time "^0.2.0" 726 | prettysize "0.0.3" 727 | realm-utils "^1.0.8" 728 | request "^2.79.0" 729 | shorthash "0.0.2" 730 | watch "^1.0.1" 731 | ws "^1.1.1" 732 | yargs "^9.0.1" 733 | 734 | fuse-test-runner@^1.0.14: 735 | version "1.0.14" 736 | resolved "https://registry.yarnpkg.com/fuse-test-runner/-/fuse-test-runner-1.0.14.tgz#9b795ade7174f3220a7e699c4b7a0d6cb72374ba" 737 | dependencies: 738 | colors "^1.1.2" 739 | diff "^3.3.0" 740 | pretty-format "^20.0.3" 741 | realm-utils "^1.0.7" 742 | 743 | fuse-tools@^1.0.4: 744 | version "1.0.5" 745 | resolved "https://registry.yarnpkg.com/fuse-tools/-/fuse-tools-1.0.5.tgz#98c9f5133348a9a91357cbf8bf57171fa6cd614a" 746 | 747 | gauge@~2.7.3: 748 | version "2.7.4" 749 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 750 | dependencies: 751 | aproba "^1.0.3" 752 | console-control-strings "^1.0.0" 753 | has-unicode "^2.0.0" 754 | object-assign "^4.1.0" 755 | signal-exit "^3.0.0" 756 | string-width "^1.0.1" 757 | strip-ansi "^3.0.1" 758 | wide-align "^1.1.0" 759 | 760 | get-caller-file@^1.0.1: 761 | version "1.0.2" 762 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" 763 | 764 | get-stream@^3.0.0: 765 | version "3.0.0" 766 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" 767 | 768 | getpass@^0.1.1: 769 | version "0.1.7" 770 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 771 | dependencies: 772 | assert-plus "^1.0.0" 773 | 774 | glob-base@^0.3.0: 775 | version "0.3.0" 776 | resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" 777 | dependencies: 778 | glob-parent "^2.0.0" 779 | is-glob "^2.0.0" 780 | 781 | glob-parent@^2.0.0: 782 | version "2.0.0" 783 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" 784 | dependencies: 785 | is-glob "^2.0.0" 786 | 787 | glob@^7.0.5: 788 | version "7.1.1" 789 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 790 | dependencies: 791 | fs.realpath "^1.0.0" 792 | inflight "^1.0.4" 793 | inherits "2" 794 | minimatch "^3.0.2" 795 | once "^1.3.0" 796 | path-is-absolute "^1.0.0" 797 | 798 | glob@^7.1.1: 799 | version "7.1.2" 800 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 801 | dependencies: 802 | fs.realpath "^1.0.0" 803 | inflight "^1.0.4" 804 | inherits "2" 805 | minimatch "^3.0.4" 806 | once "^1.3.0" 807 | path-is-absolute "^1.0.0" 808 | 809 | graceful-fs@^4.1.2, graceful-fs@^4.1.6: 810 | version "4.1.11" 811 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 812 | 813 | har-schema@^1.0.5: 814 | version "1.0.5" 815 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" 816 | 817 | har-validator@~4.2.1: 818 | version "4.2.1" 819 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" 820 | dependencies: 821 | ajv "^4.9.1" 822 | har-schema "^1.0.5" 823 | 824 | has-ansi@^2.0.0: 825 | version "2.0.0" 826 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 827 | dependencies: 828 | ansi-regex "^2.0.0" 829 | 830 | has-flag@^2.0.0: 831 | version "2.0.0" 832 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" 833 | 834 | has-unicode@^2.0.0: 835 | version "2.0.1" 836 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 837 | 838 | hawk@~3.1.3: 839 | version "3.1.3" 840 | resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" 841 | dependencies: 842 | boom "2.x.x" 843 | cryptiles "2.x.x" 844 | hoek "2.x.x" 845 | sntp "1.x.x" 846 | 847 | hoek@2.x.x: 848 | version "2.16.3" 849 | resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" 850 | 851 | hosted-git-info@^2.1.4: 852 | version "2.6.0" 853 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" 854 | 855 | http-errors@~1.6.2: 856 | version "1.6.2" 857 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" 858 | dependencies: 859 | depd "1.1.1" 860 | inherits "2.0.3" 861 | setprototypeof "1.0.3" 862 | statuses ">= 1.3.1 < 2" 863 | 864 | http-signature@~1.1.0: 865 | version "1.1.1" 866 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" 867 | dependencies: 868 | assert-plus "^0.2.0" 869 | jsprim "^1.2.2" 870 | sshpk "^1.7.0" 871 | 872 | iconv-lite@^0.4.17, iconv-lite@~0.4.13: 873 | version "0.4.18" 874 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" 875 | 876 | ieee754@^1.1.8: 877 | version "1.1.8" 878 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" 879 | 880 | inflight@^1.0.4: 881 | version "1.0.6" 882 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 883 | dependencies: 884 | once "^1.3.0" 885 | wrappy "1" 886 | 887 | inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3: 888 | version "2.0.3" 889 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 890 | 891 | ini@~1.3.0: 892 | version "1.3.4" 893 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" 894 | 895 | inquirer@3.0.6: 896 | version "3.0.6" 897 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347" 898 | dependencies: 899 | ansi-escapes "^1.1.0" 900 | chalk "^1.0.0" 901 | cli-cursor "^2.1.0" 902 | cli-width "^2.0.0" 903 | external-editor "^2.0.1" 904 | figures "^2.0.0" 905 | lodash "^4.3.0" 906 | mute-stream "0.0.7" 907 | run-async "^2.2.0" 908 | rx "^4.1.0" 909 | string-width "^2.0.0" 910 | strip-ansi "^3.0.0" 911 | through "^2.3.6" 912 | 913 | inquirer@^3.0.6: 914 | version "3.2.2" 915 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.2.2.tgz#c2aaede1507cc54d826818737742d621bef2e823" 916 | dependencies: 917 | ansi-escapes "^2.0.0" 918 | chalk "^2.0.0" 919 | cli-cursor "^2.1.0" 920 | cli-width "^2.0.0" 921 | external-editor "^2.0.4" 922 | figures "^2.0.0" 923 | lodash "^4.3.0" 924 | mute-stream "0.0.7" 925 | run-async "^2.2.0" 926 | rx-lite "^4.0.8" 927 | rx-lite-aggregates "^4.0.8" 928 | string-width "^2.1.0" 929 | strip-ansi "^4.0.0" 930 | through "^2.3.6" 931 | 932 | invert-kv@^1.0.0: 933 | version "1.0.0" 934 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" 935 | 936 | ipaddr.js@1.4.0: 937 | version "1.4.0" 938 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" 939 | 940 | is-arrayish@^0.2.1: 941 | version "0.2.1" 942 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 943 | 944 | is-binary-path@^1.0.0: 945 | version "1.0.1" 946 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" 947 | dependencies: 948 | binary-extensions "^1.0.0" 949 | 950 | is-buffer@^1.1.5: 951 | version "1.1.5" 952 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" 953 | 954 | is-builtin-module@^1.0.0: 955 | version "1.0.0" 956 | resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" 957 | dependencies: 958 | builtin-modules "^1.0.0" 959 | 960 | is-dotfile@^1.0.0: 961 | version "1.0.3" 962 | resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" 963 | 964 | is-equal-shallow@^0.1.3: 965 | version "0.1.3" 966 | resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" 967 | dependencies: 968 | is-primitive "^2.0.0" 969 | 970 | is-extendable@^0.1.1: 971 | version "0.1.1" 972 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 973 | 974 | is-extglob@^1.0.0: 975 | version "1.0.0" 976 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" 977 | 978 | is-fullwidth-code-point@^1.0.0: 979 | version "1.0.0" 980 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 981 | dependencies: 982 | number-is-nan "^1.0.0" 983 | 984 | is-fullwidth-code-point@^2.0.0: 985 | version "2.0.0" 986 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 987 | 988 | is-glob@^2.0.0, is-glob@^2.0.1: 989 | version "2.0.1" 990 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" 991 | dependencies: 992 | is-extglob "^1.0.0" 993 | 994 | is-number@^2.0.2, is-number@^2.1.0: 995 | version "2.1.0" 996 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 997 | dependencies: 998 | kind-of "^3.0.2" 999 | 1000 | is-number@^3.0.0: 1001 | version "3.0.0" 1002 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 1003 | dependencies: 1004 | kind-of "^3.0.2" 1005 | 1006 | is-posix-bracket@^0.1.0: 1007 | version "0.1.1" 1008 | resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" 1009 | 1010 | is-primitive@^2.0.0: 1011 | version "2.0.0" 1012 | resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" 1013 | 1014 | is-promise@^2.1.0: 1015 | version "2.1.0" 1016 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" 1017 | 1018 | is-stream@^1.0.1, is-stream@^1.1.0: 1019 | version "1.1.0" 1020 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 1021 | 1022 | is-typedarray@~1.0.0: 1023 | version "1.0.0" 1024 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 1025 | 1026 | isarray@1.0.0, isarray@~1.0.0: 1027 | version "1.0.0" 1028 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 1029 | 1030 | isexe@^2.0.0: 1031 | version "2.0.0" 1032 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 1033 | 1034 | isobject@^2.0.0: 1035 | version "2.1.0" 1036 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 1037 | dependencies: 1038 | isarray "1.0.0" 1039 | 1040 | isstream@~0.1.2: 1041 | version "0.1.2" 1042 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 1043 | 1044 | jsbn@~0.1.0: 1045 | version "0.1.1" 1046 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 1047 | 1048 | jschardet@^1.4.2: 1049 | version "1.5.1" 1050 | resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.5.1.tgz#c519f629f86b3a5bedba58a88d311309eec097f9" 1051 | 1052 | json-schema@0.2.3: 1053 | version "0.2.3" 1054 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 1055 | 1056 | json-stable-stringify@^1.0.1: 1057 | version "1.0.1" 1058 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 1059 | dependencies: 1060 | jsonify "~0.0.0" 1061 | 1062 | json-stringify-safe@~5.0.1: 1063 | version "5.0.1" 1064 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 1065 | 1066 | jsonfile@^2.1.0: 1067 | version "2.4.0" 1068 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" 1069 | optionalDependencies: 1070 | graceful-fs "^4.1.6" 1071 | 1072 | jsonify@~0.0.0: 1073 | version "0.0.0" 1074 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 1075 | 1076 | jsprim@^1.2.2: 1077 | version "1.4.1" 1078 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 1079 | dependencies: 1080 | assert-plus "1.0.0" 1081 | extsprintf "1.3.0" 1082 | json-schema "0.2.3" 1083 | verror "1.10.0" 1084 | 1085 | kind-of@^3.0.2: 1086 | version "3.2.2" 1087 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 1088 | dependencies: 1089 | is-buffer "^1.1.5" 1090 | 1091 | kind-of@^4.0.0: 1092 | version "4.0.0" 1093 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" 1094 | dependencies: 1095 | is-buffer "^1.1.5" 1096 | 1097 | lcid@^1.0.0: 1098 | version "1.0.0" 1099 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" 1100 | dependencies: 1101 | invert-kv "^1.0.0" 1102 | 1103 | lego-api@^1.0.7: 1104 | version "1.0.8" 1105 | resolved "https://registry.yarnpkg.com/lego-api/-/lego-api-1.0.8.tgz#5e26be726c5e11d540f89e7c6b1abf8c5834bd01" 1106 | dependencies: 1107 | chain-able "^3.0.0" 1108 | 1109 | levn@~0.3.0: 1110 | version "0.3.0" 1111 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 1112 | dependencies: 1113 | prelude-ls "~1.1.2" 1114 | type-check "~0.3.2" 1115 | 1116 | load-json-file@^2.0.0: 1117 | version "2.0.0" 1118 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" 1119 | dependencies: 1120 | graceful-fs "^4.1.2" 1121 | parse-json "^2.2.0" 1122 | pify "^2.0.0" 1123 | strip-bom "^3.0.0" 1124 | 1125 | locate-path@^2.0.0: 1126 | version "2.0.0" 1127 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" 1128 | dependencies: 1129 | p-locate "^2.0.0" 1130 | path-exists "^3.0.0" 1131 | 1132 | lodash@^4.3.0: 1133 | version "4.17.4" 1134 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 1135 | 1136 | lru-cache@^4.0.1: 1137 | version "4.1.2" 1138 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" 1139 | dependencies: 1140 | pseudomap "^1.0.2" 1141 | yallist "^2.1.2" 1142 | 1143 | media-typer@0.3.0: 1144 | version "0.3.0" 1145 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 1146 | 1147 | mem@^1.1.0: 1148 | version "1.1.0" 1149 | resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" 1150 | dependencies: 1151 | mimic-fn "^1.0.0" 1152 | 1153 | merge-descriptors@1.0.1: 1154 | version "1.0.1" 1155 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 1156 | 1157 | merge@^1.1.3: 1158 | version "1.2.0" 1159 | resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" 1160 | 1161 | methods@~1.1.2: 1162 | version "1.1.2" 1163 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 1164 | 1165 | micromatch@^2.1.5: 1166 | version "2.3.11" 1167 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" 1168 | dependencies: 1169 | arr-diff "^2.0.0" 1170 | array-unique "^0.2.1" 1171 | braces "^1.8.2" 1172 | expand-brackets "^0.1.4" 1173 | extglob "^0.3.1" 1174 | filename-regex "^2.0.0" 1175 | is-extglob "^1.0.0" 1176 | is-glob "^2.0.1" 1177 | kind-of "^3.0.2" 1178 | normalize-path "^2.0.1" 1179 | object.omit "^2.0.0" 1180 | parse-glob "^3.0.4" 1181 | regex-cache "^0.4.2" 1182 | 1183 | mime-db@~1.29.0: 1184 | version "1.29.0" 1185 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.29.0.tgz#48d26d235589651704ac5916ca06001914266878" 1186 | 1187 | mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.7: 1188 | version "2.1.16" 1189 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.16.tgz#2b858a52e5ecd516db897ac2be87487830698e23" 1190 | dependencies: 1191 | mime-db "~1.29.0" 1192 | 1193 | mime@1.3.4: 1194 | version "1.3.4" 1195 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" 1196 | 1197 | mimic-fn@^1.0.0: 1198 | version "1.1.0" 1199 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" 1200 | 1201 | minimatch@^3.0.0, minimatch@^3.0.4: 1202 | version "3.0.4" 1203 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1204 | dependencies: 1205 | brace-expansion "^1.1.7" 1206 | 1207 | minimatch@^3.0.2: 1208 | version "3.0.3" 1209 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" 1210 | dependencies: 1211 | brace-expansion "^1.0.0" 1212 | 1213 | minimist@0.0.8: 1214 | version "0.0.8" 1215 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 1216 | 1217 | minimist@1.2.0, minimist@^1.2.0: 1218 | version "1.2.0" 1219 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 1220 | 1221 | "mkdirp@>=0.5 0", mkdirp@^0.5.1: 1222 | version "0.5.1" 1223 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 1224 | dependencies: 1225 | minimist "0.0.8" 1226 | 1227 | ms@2.0.0: 1228 | version "2.0.0" 1229 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1230 | 1231 | mustache@^2.3.0: 1232 | version "2.3.0" 1233 | resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" 1234 | 1235 | mute-stream@0.0.7: 1236 | version "0.0.7" 1237 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" 1238 | 1239 | nan@^2.3.0: 1240 | version "2.6.2" 1241 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" 1242 | 1243 | nanoseconds@^0.1.0: 1244 | version "0.1.0" 1245 | resolved "https://registry.yarnpkg.com/nanoseconds/-/nanoseconds-0.1.0.tgz#69ec39fcd00e77ab3a72de0a43342824cd79233a" 1246 | 1247 | negotiator@0.6.1: 1248 | version "0.6.1" 1249 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 1250 | 1251 | node-fetch@1.6.3: 1252 | version "1.6.3" 1253 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" 1254 | dependencies: 1255 | encoding "^0.1.11" 1256 | is-stream "^1.0.1" 1257 | 1258 | node-pre-gyp@^0.6.36: 1259 | version "0.6.36" 1260 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" 1261 | dependencies: 1262 | mkdirp "^0.5.1" 1263 | nopt "^4.0.1" 1264 | npmlog "^4.0.2" 1265 | rc "^1.1.7" 1266 | request "^2.81.0" 1267 | rimraf "^2.6.1" 1268 | semver "^5.3.0" 1269 | tar "^2.2.1" 1270 | tar-pack "^3.4.0" 1271 | 1272 | nopt@^4.0.1: 1273 | version "4.0.1" 1274 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" 1275 | dependencies: 1276 | abbrev "1" 1277 | osenv "^0.1.4" 1278 | 1279 | normalize-package-data@^2.3.2: 1280 | version "2.4.0" 1281 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" 1282 | dependencies: 1283 | hosted-git-info "^2.1.4" 1284 | is-builtin-module "^1.0.0" 1285 | semver "2 || 3 || 4 || 5" 1286 | validate-npm-package-license "^3.0.1" 1287 | 1288 | normalize-path@^2.0.0, normalize-path@^2.0.1: 1289 | version "2.1.1" 1290 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" 1291 | dependencies: 1292 | remove-trailing-separator "^1.0.1" 1293 | 1294 | npm-run-path@^2.0.0: 1295 | version "2.0.2" 1296 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" 1297 | dependencies: 1298 | path-key "^2.0.0" 1299 | 1300 | npmlog@^4.0.2: 1301 | version "4.1.2" 1302 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 1303 | dependencies: 1304 | are-we-there-yet "~1.1.2" 1305 | console-control-strings "~1.1.0" 1306 | gauge "~2.7.3" 1307 | set-blocking "~2.0.0" 1308 | 1309 | number-is-nan@^1.0.0: 1310 | version "1.0.1" 1311 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 1312 | 1313 | oauth-sign@~0.8.1: 1314 | version "0.8.2" 1315 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 1316 | 1317 | object-assign@^4.0.1, object-assign@^4.1.0: 1318 | version "4.1.1" 1319 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 1320 | 1321 | object.omit@^2.0.0: 1322 | version "2.0.1" 1323 | resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" 1324 | dependencies: 1325 | for-own "^0.1.4" 1326 | is-extendable "^0.1.1" 1327 | 1328 | on-finished@~2.3.0: 1329 | version "2.3.0" 1330 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 1331 | dependencies: 1332 | ee-first "1.1.1" 1333 | 1334 | once@^1.3.0, once@^1.3.3: 1335 | version "1.4.0" 1336 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1337 | dependencies: 1338 | wrappy "1" 1339 | 1340 | onetime@^2.0.0: 1341 | version "2.0.1" 1342 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" 1343 | dependencies: 1344 | mimic-fn "^1.0.0" 1345 | 1346 | opencollective@^1.0.3: 1347 | version "1.0.3" 1348 | resolved "https://registry.yarnpkg.com/opencollective/-/opencollective-1.0.3.tgz#aee6372bc28144583690c3ca8daecfc120dd0ef1" 1349 | dependencies: 1350 | babel-polyfill "6.23.0" 1351 | chalk "1.1.3" 1352 | inquirer "3.0.6" 1353 | minimist "1.2.0" 1354 | node-fetch "1.6.3" 1355 | opn "4.0.2" 1356 | 1357 | opn@4.0.2: 1358 | version "4.0.2" 1359 | resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95" 1360 | dependencies: 1361 | object-assign "^4.0.1" 1362 | pinkie-promise "^2.0.0" 1363 | 1364 | optionator@^0.8.1: 1365 | version "0.8.2" 1366 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 1367 | dependencies: 1368 | deep-is "~0.1.3" 1369 | fast-levenshtein "~2.0.4" 1370 | levn "~0.3.0" 1371 | prelude-ls "~1.1.2" 1372 | type-check "~0.3.2" 1373 | wordwrap "~1.0.0" 1374 | 1375 | options@>=0.0.5: 1376 | version "0.0.6" 1377 | resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" 1378 | 1379 | os-homedir@^1.0.0: 1380 | version "1.0.2" 1381 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 1382 | 1383 | os-locale@^2.0.0: 1384 | version "2.1.0" 1385 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" 1386 | dependencies: 1387 | execa "^0.7.0" 1388 | lcid "^1.0.0" 1389 | mem "^1.1.0" 1390 | 1391 | os-tmpdir@^1.0.0, os-tmpdir@~1.0.1: 1392 | version "1.0.2" 1393 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 1394 | 1395 | osenv@^0.1.4: 1396 | version "0.1.4" 1397 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" 1398 | dependencies: 1399 | os-homedir "^1.0.0" 1400 | os-tmpdir "^1.0.0" 1401 | 1402 | p-finally@^1.0.0: 1403 | version "1.0.0" 1404 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" 1405 | 1406 | p-limit@^1.1.0: 1407 | version "1.2.0" 1408 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" 1409 | dependencies: 1410 | p-try "^1.0.0" 1411 | 1412 | p-locate@^2.0.0: 1413 | version "2.0.0" 1414 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" 1415 | dependencies: 1416 | p-limit "^1.1.0" 1417 | 1418 | p-try@^1.0.0: 1419 | version "1.0.0" 1420 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" 1421 | 1422 | parse-glob@^3.0.4: 1423 | version "3.0.4" 1424 | resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" 1425 | dependencies: 1426 | glob-base "^0.3.0" 1427 | is-dotfile "^1.0.0" 1428 | is-extglob "^1.0.0" 1429 | is-glob "^2.0.0" 1430 | 1431 | parse-json@^2.2.0: 1432 | version "2.2.0" 1433 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 1434 | dependencies: 1435 | error-ex "^1.2.0" 1436 | 1437 | parseurl@~1.3.1: 1438 | version "1.3.1" 1439 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" 1440 | 1441 | path-exists@^3.0.0: 1442 | version "3.0.0" 1443 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 1444 | 1445 | path-is-absolute@^1.0.0: 1446 | version "1.0.1" 1447 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1448 | 1449 | path-key@^2.0.0: 1450 | version "2.0.1" 1451 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 1452 | 1453 | path-to-regexp@0.1.7: 1454 | version "0.1.7" 1455 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 1456 | 1457 | path-type@^2.0.0: 1458 | version "2.0.0" 1459 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" 1460 | dependencies: 1461 | pify "^2.0.0" 1462 | 1463 | performance-now@^0.2.0: 1464 | version "0.2.0" 1465 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" 1466 | 1467 | pify@^2.0.0: 1468 | version "2.3.0" 1469 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 1470 | 1471 | pinkie-promise@^2.0.0: 1472 | version "2.0.1" 1473 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 1474 | dependencies: 1475 | pinkie "^2.0.0" 1476 | 1477 | pinkie@^2.0.0: 1478 | version "2.0.4" 1479 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 1480 | 1481 | postcss@^6.0.1: 1482 | version "6.0.10" 1483 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.10.tgz#c311b89734483d87a91a56dc9e53f15f4e6e84e4" 1484 | dependencies: 1485 | chalk "^2.1.0" 1486 | source-map "^0.5.7" 1487 | supports-color "^4.2.1" 1488 | 1489 | prelude-ls@~1.1.2: 1490 | version "1.1.2" 1491 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 1492 | 1493 | preserve@^0.2.0: 1494 | version "0.2.0" 1495 | resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" 1496 | 1497 | pretty-format@^20.0.3: 1498 | version "20.0.3" 1499 | resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-20.0.3.tgz#020e350a560a1fe1a98dc3beb6ccffb386de8b14" 1500 | dependencies: 1501 | ansi-regex "^2.1.1" 1502 | ansi-styles "^3.0.0" 1503 | 1504 | pretty-time@^0.2.0: 1505 | version "0.2.0" 1506 | resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-0.2.0.tgz#7a3bdec4049c620cd7c42b7f342b74d56e73d74e" 1507 | dependencies: 1508 | is-number "^2.0.2" 1509 | nanoseconds "^0.1.0" 1510 | 1511 | prettysize@0.0.3: 1512 | version "0.0.3" 1513 | resolved "https://registry.yarnpkg.com/prettysize/-/prettysize-0.0.3.tgz#14afff6a645e591a4ddf1c72919c23b4146181a1" 1514 | 1515 | process-nextick-args@~1.0.6: 1516 | version "1.0.7" 1517 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 1518 | 1519 | proxy-addr@~1.1.5: 1520 | version "1.1.5" 1521 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918" 1522 | dependencies: 1523 | forwarded "~0.1.0" 1524 | ipaddr.js "1.4.0" 1525 | 1526 | pseudomap@^1.0.2: 1527 | version "1.0.2" 1528 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" 1529 | 1530 | punycode@^1.4.1: 1531 | version "1.4.1" 1532 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 1533 | 1534 | qs@6.5.0: 1535 | version "6.5.0" 1536 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" 1537 | 1538 | qs@~6.4.0: 1539 | version "6.4.0" 1540 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 1541 | 1542 | randomatic@^1.1.3: 1543 | version "1.1.7" 1544 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" 1545 | dependencies: 1546 | is-number "^3.0.0" 1547 | kind-of "^4.0.0" 1548 | 1549 | range-parser@~1.2.0: 1550 | version "1.2.0" 1551 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 1552 | 1553 | rc@^1.1.7: 1554 | version "1.2.1" 1555 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" 1556 | dependencies: 1557 | deep-extend "~0.4.0" 1558 | ini "~1.3.0" 1559 | minimist "^1.2.0" 1560 | strip-json-comments "~2.0.1" 1561 | 1562 | read-pkg-up@^2.0.0: 1563 | version "2.0.0" 1564 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" 1565 | dependencies: 1566 | find-up "^2.0.0" 1567 | read-pkg "^2.0.0" 1568 | 1569 | read-pkg@^2.0.0: 1570 | version "2.0.0" 1571 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" 1572 | dependencies: 1573 | load-json-file "^2.0.0" 1574 | normalize-package-data "^2.3.2" 1575 | path-type "^2.0.0" 1576 | 1577 | readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4: 1578 | version "2.3.3" 1579 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" 1580 | dependencies: 1581 | core-util-is "~1.0.0" 1582 | inherits "~2.0.3" 1583 | isarray "~1.0.0" 1584 | process-nextick-args "~1.0.6" 1585 | safe-buffer "~5.1.1" 1586 | string_decoder "~1.0.3" 1587 | util-deprecate "~1.0.1" 1588 | 1589 | readdirp@^2.0.0: 1590 | version "2.1.0" 1591 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" 1592 | dependencies: 1593 | graceful-fs "^4.1.2" 1594 | minimatch "^3.0.2" 1595 | readable-stream "^2.0.2" 1596 | set-immediate-shim "^1.0.1" 1597 | 1598 | realm-utils@^1.0.7, realm-utils@^1.0.8: 1599 | version "1.0.8" 1600 | resolved "https://registry.yarnpkg.com/realm-utils/-/realm-utils-1.0.8.tgz#7f8c87c30cee0cd295ecf732a049cc1d7502da8f" 1601 | dependencies: 1602 | app-root-path "^1.3.0" 1603 | mkdirp "^0.5.1" 1604 | 1605 | regenerator-runtime@^0.10.0: 1606 | version "0.10.5" 1607 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" 1608 | 1609 | regenerator-runtime@^0.11.0: 1610 | version "0.11.0" 1611 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" 1612 | 1613 | regex-cache@^0.4.2: 1614 | version "0.4.3" 1615 | resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" 1616 | dependencies: 1617 | is-equal-shallow "^0.1.3" 1618 | is-primitive "^2.0.0" 1619 | 1620 | remove-trailing-separator@^1.0.1: 1621 | version "1.1.0" 1622 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" 1623 | 1624 | repeat-element@^1.1.2: 1625 | version "1.1.2" 1626 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" 1627 | 1628 | repeat-string@^1.5.2: 1629 | version "1.6.1" 1630 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 1631 | 1632 | request@^2.79.0, request@^2.81.0: 1633 | version "2.81.0" 1634 | resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" 1635 | dependencies: 1636 | aws-sign2 "~0.6.0" 1637 | aws4 "^1.2.1" 1638 | caseless "~0.12.0" 1639 | combined-stream "~1.0.5" 1640 | extend "~3.0.0" 1641 | forever-agent "~0.6.1" 1642 | form-data "~2.1.1" 1643 | har-validator "~4.2.1" 1644 | hawk "~3.1.3" 1645 | http-signature "~1.1.0" 1646 | is-typedarray "~1.0.0" 1647 | isstream "~0.1.2" 1648 | json-stringify-safe "~5.0.1" 1649 | mime-types "~2.1.7" 1650 | oauth-sign "~0.8.1" 1651 | performance-now "^0.2.0" 1652 | qs "~6.4.0" 1653 | safe-buffer "^5.0.1" 1654 | stringstream "~0.0.4" 1655 | tough-cookie "~2.3.0" 1656 | tunnel-agent "^0.6.0" 1657 | uuid "^3.0.0" 1658 | 1659 | require-directory@^2.1.1: 1660 | version "2.1.1" 1661 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 1662 | 1663 | require-main-filename@^1.0.1: 1664 | version "1.0.1" 1665 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" 1666 | 1667 | restore-cursor@^2.0.0: 1668 | version "2.0.0" 1669 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" 1670 | dependencies: 1671 | onetime "^2.0.0" 1672 | signal-exit "^3.0.2" 1673 | 1674 | rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: 1675 | version "2.6.1" 1676 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" 1677 | dependencies: 1678 | glob "^7.0.5" 1679 | 1680 | rimraf@^2.6.2: 1681 | version "2.6.2" 1682 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" 1683 | dependencies: 1684 | glob "^7.0.5" 1685 | 1686 | run-async@^2.2.0: 1687 | version "2.3.0" 1688 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" 1689 | dependencies: 1690 | is-promise "^2.1.0" 1691 | 1692 | rx-lite-aggregates@^4.0.8: 1693 | version "4.0.8" 1694 | resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" 1695 | dependencies: 1696 | rx-lite "*" 1697 | 1698 | rx-lite@*, rx-lite@^4.0.8: 1699 | version "4.0.8" 1700 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" 1701 | 1702 | rx@^4.1.0: 1703 | version "4.1.0" 1704 | resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" 1705 | 1706 | safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1707 | version "5.1.1" 1708 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 1709 | 1710 | "semver@2 || 3 || 4 || 5": 1711 | version "5.5.0" 1712 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" 1713 | 1714 | semver@^5.3.0: 1715 | version "5.4.1" 1716 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" 1717 | 1718 | send@0.15.4: 1719 | version "0.15.4" 1720 | resolved "https://registry.yarnpkg.com/send/-/send-0.15.4.tgz#985faa3e284b0273c793364a35c6737bd93905b9" 1721 | dependencies: 1722 | debug "2.6.8" 1723 | depd "~1.1.1" 1724 | destroy "~1.0.4" 1725 | encodeurl "~1.0.1" 1726 | escape-html "~1.0.3" 1727 | etag "~1.8.0" 1728 | fresh "0.5.0" 1729 | http-errors "~1.6.2" 1730 | mime "1.3.4" 1731 | ms "2.0.0" 1732 | on-finished "~2.3.0" 1733 | range-parser "~1.2.0" 1734 | statuses "~1.3.1" 1735 | 1736 | serve-static@1.12.4: 1737 | version "1.12.4" 1738 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.4.tgz#9b6aa98eeb7253c4eedc4c1f6fdbca609901a961" 1739 | dependencies: 1740 | encodeurl "~1.0.1" 1741 | escape-html "~1.0.3" 1742 | parseurl "~1.3.1" 1743 | send "0.15.4" 1744 | 1745 | set-blocking@^2.0.0, set-blocking@~2.0.0: 1746 | version "2.0.0" 1747 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1748 | 1749 | set-immediate-shim@^1.0.1: 1750 | version "1.0.1" 1751 | resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" 1752 | 1753 | setprototypeof@1.0.3: 1754 | version "1.0.3" 1755 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 1756 | 1757 | shebang-command@^1.2.0: 1758 | version "1.2.0" 1759 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 1760 | dependencies: 1761 | shebang-regex "^1.0.0" 1762 | 1763 | shebang-regex@^1.0.0: 1764 | version "1.0.0" 1765 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 1766 | 1767 | shorthash@0.0.2: 1768 | version "0.0.2" 1769 | resolved "https://registry.yarnpkg.com/shorthash/-/shorthash-0.0.2.tgz#59b268eecbde59038b30da202bcfbddeb2c4a4eb" 1770 | 1771 | signal-exit@^3.0.0, signal-exit@^3.0.2: 1772 | version "3.0.2" 1773 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1774 | 1775 | sntp@1.x.x: 1776 | version "1.0.9" 1777 | resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" 1778 | dependencies: 1779 | hoek "2.x.x" 1780 | 1781 | source-map@^0.5.1, source-map@^0.5.7: 1782 | version "0.5.7" 1783 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 1784 | 1785 | source-map@~0.2.0: 1786 | version "0.2.0" 1787 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" 1788 | dependencies: 1789 | amdefine ">=0.0.4" 1790 | 1791 | spdx-correct@^3.0.0: 1792 | version "3.0.0" 1793 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" 1794 | dependencies: 1795 | spdx-expression-parse "^3.0.0" 1796 | spdx-license-ids "^3.0.0" 1797 | 1798 | spdx-exceptions@^2.1.0: 1799 | version "2.1.0" 1800 | resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" 1801 | 1802 | spdx-expression-parse@^3.0.0: 1803 | version "3.0.0" 1804 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" 1805 | dependencies: 1806 | spdx-exceptions "^2.1.0" 1807 | spdx-license-ids "^3.0.0" 1808 | 1809 | spdx-license-ids@^3.0.0: 1810 | version "3.0.0" 1811 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" 1812 | 1813 | sshpk@^1.7.0: 1814 | version "1.13.1" 1815 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" 1816 | dependencies: 1817 | asn1 "~0.2.3" 1818 | assert-plus "^1.0.0" 1819 | dashdash "^1.12.0" 1820 | getpass "^0.1.1" 1821 | optionalDependencies: 1822 | bcrypt-pbkdf "^1.0.0" 1823 | ecc-jsbn "~0.1.1" 1824 | jsbn "~0.1.0" 1825 | tweetnacl "~0.14.0" 1826 | 1827 | "statuses@>= 1.3.1 < 2", statuses@~1.3.1: 1828 | version "1.3.1" 1829 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 1830 | 1831 | string-width@^1.0.1, string-width@^1.0.2: 1832 | version "1.0.2" 1833 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1834 | dependencies: 1835 | code-point-at "^1.0.0" 1836 | is-fullwidth-code-point "^1.0.0" 1837 | strip-ansi "^3.0.0" 1838 | 1839 | string-width@^2.0.0, string-width@^2.1.0: 1840 | version "2.1.1" 1841 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1842 | dependencies: 1843 | is-fullwidth-code-point "^2.0.0" 1844 | strip-ansi "^4.0.0" 1845 | 1846 | string_decoder@~1.0.3: 1847 | version "1.0.3" 1848 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" 1849 | dependencies: 1850 | safe-buffer "~5.1.0" 1851 | 1852 | stringstream@~0.0.4: 1853 | version "0.0.5" 1854 | resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" 1855 | 1856 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 1857 | version "3.0.1" 1858 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1859 | dependencies: 1860 | ansi-regex "^2.0.0" 1861 | 1862 | strip-ansi@^4.0.0: 1863 | version "4.0.0" 1864 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1865 | dependencies: 1866 | ansi-regex "^3.0.0" 1867 | 1868 | strip-bom@^3.0.0: 1869 | version "3.0.0" 1870 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 1871 | 1872 | strip-eof@^1.0.0: 1873 | version "1.0.0" 1874 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" 1875 | 1876 | strip-json-comments@~2.0.1: 1877 | version "2.0.1" 1878 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1879 | 1880 | supports-color@^2.0.0: 1881 | version "2.0.0" 1882 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 1883 | 1884 | supports-color@^4.0.0, supports-color@^4.2.1: 1885 | version "4.2.1" 1886 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.1.tgz#65a4bb2631e90e02420dba5554c375a4754bb836" 1887 | dependencies: 1888 | has-flag "^2.0.0" 1889 | 1890 | tar-pack@^3.4.0: 1891 | version "3.4.0" 1892 | resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" 1893 | dependencies: 1894 | debug "^2.2.0" 1895 | fstream "^1.0.10" 1896 | fstream-ignore "^1.0.5" 1897 | once "^1.3.3" 1898 | readable-stream "^2.1.4" 1899 | rimraf "^2.5.1" 1900 | tar "^2.2.1" 1901 | uid-number "^0.0.6" 1902 | 1903 | tar@^2.2.1: 1904 | version "2.2.1" 1905 | resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" 1906 | dependencies: 1907 | block-stream "*" 1908 | fstream "^1.0.2" 1909 | inherits "2" 1910 | 1911 | through@^2.3.6: 1912 | version "2.3.8" 1913 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1914 | 1915 | tmp@^0.0.31: 1916 | version "0.0.31" 1917 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" 1918 | dependencies: 1919 | os-tmpdir "~1.0.1" 1920 | 1921 | tough-cookie@~2.3.0: 1922 | version "2.3.2" 1923 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" 1924 | dependencies: 1925 | punycode "^1.4.1" 1926 | 1927 | tunnel-agent@^0.6.0: 1928 | version "0.6.0" 1929 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 1930 | dependencies: 1931 | safe-buffer "^5.0.1" 1932 | 1933 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 1934 | version "0.14.5" 1935 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 1936 | 1937 | type-check@~0.3.2: 1938 | version "0.3.2" 1939 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 1940 | dependencies: 1941 | prelude-ls "~1.1.2" 1942 | 1943 | type-is@~1.6.15: 1944 | version "1.6.15" 1945 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" 1946 | dependencies: 1947 | media-typer "0.3.0" 1948 | mime-types "~2.1.15" 1949 | 1950 | typescript@^2.8.1: 1951 | version "2.8.1" 1952 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624" 1953 | 1954 | uid-number@^0.0.6: 1955 | version "0.0.6" 1956 | resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" 1957 | 1958 | ultron@1.0.x: 1959 | version "1.0.2" 1960 | resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" 1961 | 1962 | unpipe@~1.0.0: 1963 | version "1.0.0" 1964 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1965 | 1966 | util-deprecate@~1.0.1: 1967 | version "1.0.2" 1968 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1969 | 1970 | utils-extend@^1.0.4, utils-extend@^1.0.6, utils-extend@^1.0.7: 1971 | version "1.0.8" 1972 | resolved "https://registry.yarnpkg.com/utils-extend/-/utils-extend-1.0.8.tgz#ccfd7b64540f8e90ee21eec57769d0651cab8a5f" 1973 | 1974 | utils-merge@1.0.0: 1975 | version "1.0.0" 1976 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" 1977 | 1978 | uuid@^3.0.0: 1979 | version "3.1.0" 1980 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" 1981 | 1982 | validate-npm-package-license@^3.0.1: 1983 | version "3.0.3" 1984 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" 1985 | dependencies: 1986 | spdx-correct "^3.0.0" 1987 | spdx-expression-parse "^3.0.0" 1988 | 1989 | vary@~1.1.1: 1990 | version "1.1.1" 1991 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" 1992 | 1993 | verror@1.10.0: 1994 | version "1.10.0" 1995 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 1996 | dependencies: 1997 | assert-plus "^1.0.0" 1998 | core-util-is "1.0.2" 1999 | extsprintf "^1.2.0" 2000 | 2001 | watch@^1.0.1: 2002 | version "1.0.2" 2003 | resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" 2004 | dependencies: 2005 | exec-sh "^0.2.0" 2006 | minimist "^1.2.0" 2007 | 2008 | which-module@^2.0.0: 2009 | version "2.0.0" 2010 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 2011 | 2012 | which@^1.2.9: 2013 | version "1.3.0" 2014 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" 2015 | dependencies: 2016 | isexe "^2.0.0" 2017 | 2018 | wide-align@^1.1.0: 2019 | version "1.1.2" 2020 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" 2021 | dependencies: 2022 | string-width "^1.0.2" 2023 | 2024 | wordwrap@~1.0.0: 2025 | version "1.0.0" 2026 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 2027 | 2028 | wrap-ansi@^2.0.0: 2029 | version "2.1.0" 2030 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" 2031 | dependencies: 2032 | string-width "^1.0.1" 2033 | strip-ansi "^3.0.1" 2034 | 2035 | wrappy@1: 2036 | version "1.0.2" 2037 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 2038 | 2039 | ws@^1.1.1: 2040 | version "1.1.4" 2041 | resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" 2042 | dependencies: 2043 | options ">=0.0.5" 2044 | ultron "1.0.x" 2045 | 2046 | y18n@^3.2.1: 2047 | version "3.2.1" 2048 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" 2049 | 2050 | yallist@^2.1.2: 2051 | version "2.1.2" 2052 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" 2053 | 2054 | yargs-parser@^7.0.0: 2055 | version "7.0.0" 2056 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" 2057 | dependencies: 2058 | camelcase "^4.1.0" 2059 | 2060 | yargs@^9.0.1: 2061 | version "9.0.1" 2062 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" 2063 | dependencies: 2064 | camelcase "^4.1.0" 2065 | cliui "^3.2.0" 2066 | decamelize "^1.1.1" 2067 | get-caller-file "^1.0.1" 2068 | os-locale "^2.0.0" 2069 | read-pkg-up "^2.0.0" 2070 | require-directory "^2.1.1" 2071 | require-main-filename "^1.0.1" 2072 | set-blocking "^2.0.0" 2073 | string-width "^2.0.0" 2074 | which-module "^2.0.0" 2075 | y18n "^3.2.1" 2076 | yargs-parser "^7.0.0" 2077 | --------------------------------------------------------------------------------