├── .editorconfig ├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── examples ├── relay │ ├── db.js │ ├── package.json │ ├── schema │ │ ├── interfaces │ │ │ └── employee.js │ │ └── types │ │ │ ├── group │ │ │ ├── index.js │ │ │ ├── mutations │ │ │ │ ├── create-group.js │ │ │ │ └── index.js │ │ │ └── queries │ │ │ │ ├── group.js │ │ │ │ ├── groups.js │ │ │ │ └── index.js │ │ │ └── user │ │ │ ├── index.js │ │ │ ├── mutations │ │ │ ├── create-user.js │ │ │ └── index.js │ │ │ └── queries │ │ │ ├── index.js │ │ │ ├── user.js │ │ │ └── users.js │ └── server.js └── simple │ ├── db.js │ ├── package.json │ ├── schema │ ├── interfaces │ │ └── employee.js │ └── types │ │ ├── group │ │ ├── index.js │ │ ├── mutations │ │ │ ├── create-group.js │ │ │ └── index.js │ │ └── queries │ │ │ ├── group.js │ │ │ ├── groups.js │ │ │ └── index.js │ │ └── user │ │ ├── index.js │ │ ├── mutations │ │ ├── create-user.js │ │ └── index.js │ │ └── queries │ │ ├── index.js │ │ ├── user.js │ │ └── users.js │ └── server.js ├── extensions ├── graylay │ └── index.js └── load-from-dir │ └── index.js ├── index.js ├── lib ├── graysql.js ├── graysql │ ├── interface.js │ ├── mutation.js │ ├── query.js │ └── type.js └── utils │ ├── index.js │ └── type-parser.js ├── package.json ├── test ├── index.js ├── support │ ├── db.js │ ├── extensions │ │ └── test-extension.js │ ├── test-schema-dir │ │ ├── interfaces │ │ │ └── employee.js │ │ ├── relay-types │ │ │ ├── group │ │ │ │ ├── index.js │ │ │ │ └── queries │ │ │ │ │ └── group.js │ │ │ └── user │ │ │ │ ├── index.js │ │ │ │ └── queries │ │ │ │ └── user.js │ │ └── types │ │ │ ├── group │ │ │ ├── index.js │ │ │ └── queries │ │ │ │ └── group.js │ │ │ └── user │ │ │ ├── index.js │ │ │ ├── mutations │ │ │ └── create-user.js │ │ │ └── queries │ │ │ └── user.js │ ├── test-schema-relay.js │ ├── test-schema.js │ └── types │ │ ├── group.js │ │ ├── simple.js │ │ └── user.js └── unit │ ├── extensions │ ├── graylay │ │ └── index.js │ └── load-from-dir │ │ └── index.js │ ├── graysql.js │ ├── graysql │ ├── interface.js │ ├── mutation.js │ ├── query.js │ └── type.js │ └── utils │ ├── index.js │ └── type-parser.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | 4 | [*] 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "es6": true, 5 | "node": true 6 | }, 7 | "ecmaFeatures": { 8 | "destructuring": true 9 | }, 10 | "rules": { 11 | "strict": 0, 12 | "no-console": 0, 13 | "no-unused-vars": 1, 14 | "no-var": 1, 15 | "prefer-const": 1, 16 | "no-trailing-spaces": 1, 17 | "comma-dangle": [1, "always"], 18 | "quotes": [2, "single"], 19 | "indent": [2, 2, { "SwitchCase": 2 }], 20 | "semi": [2, "always"] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | dist 4 | coverage 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2016 Lars Ruiz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraysQL # 2 | 3 | GraysQL is a manager and loader for [GraphQL](http://graphql.org). It provides a uniform way of 4 | organize your GraphQL schema. GraphQL tries to create an easy to read codebase. It features a 5 | plugins API to allow the extension of the core functionalities. 6 | 7 | It's directly compatible with the [GraphQL](http://github.com/graphql/graphql-js) reference 8 | implementation. 9 | 10 | 11 | ## Installation ## 12 | 13 | Install from NPM. You need to install it's peer dependencies if you haven't done yet too. 14 | 15 | ```bash 16 | $ npm install --save graysql graphql graphql-relay 17 | ``` 18 | 19 | 20 | ## Examples ## 21 | 22 | Here is a simple example to get started: 23 | 24 | ```javascript 25 | const GraphQLUtils = require('graphql/utilities'); 26 | const GraysQL = require('graysql'); 27 | const Graylay = require('graysql/extensions/graylay'); // Add support for Relay entities 28 | const DB = require('./db'); // Mockup data source 29 | 30 | const GQL = new GraysQL({ 31 | DB: DB 32 | }); 33 | 34 | // Add some extensions 35 | GQL.use(Graylay); 36 | 37 | // You can import types 38 | GQL.registerType(require('./types/group')); 39 | 40 | // Or define them inline 41 | GQL.registerType(function (GQL, types) { 42 | return { 43 | name: 'User', 44 | nodeId: id => GQL.options.DB.getUser(id), 45 | isTypeOf: obj => obj instanceof GQL.options.DB.User, 46 | interfaces: ['Node'], 47 | fields: { 48 | id: { 49 | type: 'Int' 50 | }, 51 | nick: { 52 | type: 'String' 53 | }, 54 | group: { 55 | type: 'Group' // Define type dependencies 56 | } 57 | }, 58 | queries: { 59 | user: { // You can define inline queries 60 | type: 'User', 61 | args: { 62 | id: { 63 | type: 'Int' 64 | } 65 | }, 66 | resolve: (_, args) => GQL.options.DB.getUser(args.id); 67 | }, 68 | users: require('./queries/users') // Or import them 69 | } 70 | } 71 | }); 72 | 73 | 74 | const Schema = GQL.generateSchema(); 75 | console.log(GraphQLUtils.printSchema(Schema)); 76 | ``` 77 | 78 | 79 | ## Overview ## 80 | 81 | ### Type ### 82 | 83 | A [Type](lib/graysql/type.js) is a representation of a 84 | [GraphQLObjectType](http://graphql.org/docs/api-reference-type-system/#graphqlobjecttype). Types are 85 | the main object in GraysQL and every other object relates to them in some way. They define the 86 | layout of your schema. To create a new Type simply create a JavaScript function that takes an 87 | argument that is a reference to the current GraysQL instance and that function should return an 88 | object with the keys needed to create an object. 89 | 90 | The mandatory keys are: 91 | 92 | * `name`: A string representing the name of the type that will be used to create and store it. 93 | Other types will use this name to reference the type as well. 94 | * `fields`: An object representing the fields of the type. This is directly related to the 95 | `fields` property in GraphQLObjectType. 96 | 97 | The type of the field is specified as a string instead of a [GraphQLScalarType](). The basic list 98 | of supported types is: 99 | 100 | * `Int`: Translates to 101 | [GraphQLInt](http://graphql.org/docs/api-reference-type-system/#graphqlint) 102 | * `String`: Translates to 103 | [GraphQLString](http://graphql.org/docs/api-reference-type-system/#graphqlstring) 104 | * `TypeName`: Reference another type in the system. 105 | * `[TypeName]`: Reference an array of another type in the system. Equivalent to 106 | [GraphQLList](http://graphql.org/docs/api-reference-type-system/#graphqllist). 107 | 108 | Besides that, [extensions](https://github.com/larsbs/graysql#extensions) can define custom keys or 109 | even you can define your own keys if you need it. 110 | 111 | #### Example Types #### 112 | 113 | Types can be defined in its own file. For example, `types/user.js` and `types/group.js`. 114 | 115 | ```javascript 116 | 117 | // types/user.js 118 | module.exports = function (GQL) { 119 | return { 120 | name: 'User', 121 | fields: { 122 | id: { type: 'Int' }, 123 | nick: { type: 'String' }, 124 | group: { type: 'String' } 125 | } 126 | }; 127 | } 128 | 129 | // types/group.js 130 | module.exports = function (GQL) { 131 | return { 132 | name: 'Group', 133 | fields: { 134 | id: { type: 'Int' }, 135 | nick: { type: 'String' }, 136 | members: { type: '[User]' } 137 | } 138 | }; 139 | } 140 | ``` 141 | 142 | When the two types are defined, we can register them within the system: 143 | 144 | ```javascript 145 | const GraysQL = require('graysql'); 146 | 147 | const GQL = new GraysQL(); 148 | GQL.registerType(require('./types/user.js')); 149 | GQL.registerType(require('./types/group.js')); 150 | ``` 151 | 152 | ### Interfaces ### 153 | TODO 154 | 155 | ### Query ### 156 | 157 | In order to make request to the 158 | [Schema](http://graphql.org/docs/api-reference-type-system/#graphqlschema) you must define Queries 159 | in your [Types](https://github.com/larsbs/graysql#type). As queries are only plain Javascript 160 | object, they can be defined inline in your types or in separate files and later exported. However, 161 | if you define your queries in standalone files, you should wrap them in a function. This function, 162 | like types, will receive a single parameter that is the current GQL intance, and should return the 163 | query object. 164 | 165 | Once a query is defined, you can add it to the sytem using two ways. Embedding them in a type, like 166 | the first example, or using the auxiliar function `GQL.addQuery(query)`. 167 | 168 | The query object should have three keys that are mandatory: 169 | 170 | * `type`: The type to which the query is applied. It has to be registered in the system before the 171 | query will be generated. 172 | * `args`: It's equivalent to `args` in 173 | [GraphQL queries](http://graphql.org/docs/getting-started/#server). It uses the same syntax for 174 | types than the key `fields` in [Types](https://github.com/larsbs/graysql#type). 175 | * `resolve`: It's the same as `resolve` in 176 | [GraphQL queries](http://graphql.org/docs/getting-started/#server). 177 | 178 | #### Example Queries #### 179 | 180 | ```javascript 181 | // queries/user.js 182 | module.exports = function (GQL) { 183 | return { 184 | type: 'User', 185 | args: { 186 | id: { type: 'Int' } 187 | }, 188 | resolve: (_, args) => GQL.options.DB.getUser(args.id) 189 | } 190 | } 191 | 192 | // index.js 193 | GQL.addQuery('user', require('./queries/user')); 194 | ``` 195 | 196 | ### Mutations ### 197 | TODO 198 | 199 | ## GraysQL ## 200 | 201 | ### Constructor ### 202 | 203 | #### `new GraysQL(options)` #### 204 | > GraysQL is initialized by passing an object with any number of custom keys. This keys will be 205 | > available later in the GraysQL instance. 206 | 207 | ```javascript 208 | const DB = require('./db'); 209 | const GraysQL = require('graysql'); 210 | const GQL = new GraysQL({ 211 | DB: DB 212 | }); 213 | console.log(GQL.options.DB); 214 | ``` 215 | 216 | ### Methods ### 217 | 218 | #### `GraysQL.use(extension)` #### 219 | > Receives a GraysQL extension and add it to GraysQL. 220 | 221 | * **Parameters** 222 | * `extension` *Function*: A valid [extension]() to be added. 223 | 224 | ```javascript 225 | const GraysQL = require('graysql'); 226 | const LoadFromDir = require('graysql/extensions/load-from-dir'); 227 | const Graylay = require('graysql/extensions/graylay'); 228 | 229 | const GQL = new GraysQL(); 230 | GQL.use(LoadFromDir); 231 | GQL.use(Graylay); 232 | ``` 233 | 234 | #### `GQL.registerType(type, [overwrite])` #### 235 | > Registers a new type in the system. 236 | 237 | * **Parameters** 238 | * `type` *Function*: A valid [type](https://github.com/larsbs/graysql#type) to be registered. 239 | * `overwrite` *Boolean*: A flag wether the registered type should overwrite an existent type 240 | with the same name or not. 241 | * **Returns** 242 | * *Object*: The registered type. 243 | 244 | ```javascript 245 | const GraysQL = require('graysql'); 246 | const GQL = new GraysQL(); 247 | 248 | const UserType = function (GQL) { 249 | return { 250 | name: 'User', 251 | fields: { 252 | id: { type: 'Int' }, 253 | nick: { type: 'String' } 254 | } 255 | }; 256 | } 257 | 258 | GQL.registerType(UserType); 259 | ``` 260 | 261 | #### `GQL.registerInterface(interface, [overwrite])` #### 262 | > Registers a new interface in the system that can be later implemented by types. Interfaces should 263 | > be registered before the implementing types. 264 | 265 | * **Parameters** 266 | * `interface` *Function*: A valid [interface](https://github.com/larsbs/graysql#interface) to be 267 | registered. 268 | * `overwrite` *Boolean*: A flag wether the registered interface should overwrite an existent 269 | interface with the same name or not. 270 | * **Returns** 271 | * *Object*: The registered interface. 272 | 273 | ```javascript 274 | const GraysQL = require('graysql'); 275 | const GQL = new GraysQL(); 276 | 277 | const EmployeeInterface = function (GQL) { 278 | return { 279 | name: 'Employee', 280 | fields: { 281 | employeeId: { type: 'Int' } 282 | } 283 | }; 284 | } 285 | GQL.registerInterface(EmployeeInterface); 286 | ``` 287 | 288 | #### `GQL.addQuery(name, query, [overwrite])` #### 289 | > Adds a new query to the system. Note that if the type of the query is not already registered in 290 | > the system, this will throw an error. 291 | 292 | * **Parameters** 293 | * `name` *String*: The name of the query to be added. 294 | * `query` *Function*: A valid [query](https://github.com/larsbs/graysql#query) to be added. 295 | * `overwrite` *Boolean*: A flag wether the added query should overwrite an existent query with 296 | the same name or not. 297 | * **Returns** 298 | * *Object*: The added query. 299 | 300 | #### `GQL.addMutation(name, mutation, [overwrite])` #### 301 | > Adds a new mutation to the system. Note that if the type of the mutation is not already registered 302 | > in the system, this will throw an error. 303 | 304 | * **Parameters** 305 | * `name` *String*: The name of the mutation to be added. 306 | * `mutation` *Function*: A valid [mutation](https://github.com/larsbs/graysql#mutation) to be 307 | added. 308 | * `overwrite` *Boolean*: A flag wether the added mutation should overwrite an existent mutation 309 | with the same name or not. 310 | * **Returns** 311 | * *Object*: The added mutation. 312 | 313 | #### `GQL.generateSchema()` #### 314 | > Generates a [GraphQLSchema](http://graphql.org/docs/api-reference-type-system/#graphqlschema) from 315 | > the registered objects. 316 | 317 | * **Returns** 318 | * *GraphQLSchema*: The generated schema. 319 | 320 | ## Extensions ## 321 | 322 | ### [ORMLoader](https://github.com/larsbs/graysql-orm-loader) ### 323 | 324 | Loads the models defined with an ORM into GraysQL to generate a Schema from them. More in the 325 | project [repository](https://github.com/larsbs/graysql-orm-loader). 326 | 327 | ### LoadFromDir ### 328 | 329 | Allows GraysQL to scan a folder to build a schema from the files found. You only need to define your 330 | schema and GraysQL will take care of the registration process for you. This way, you can model your 331 | schema from the dir structure. This allows you to add or delete objects on the fly, without having 332 | to register the new ones, or de-register the old ones 333 | 334 | The folder structure that LoadFromDir will search for it's: 335 | 336 | ```plain 337 | schema/ 338 | ├── types/ 339 | │ ├── type-name/ 340 | │ │ └── index.js 341 | ├── interfaces/ 342 | │ └── interface-name.js 343 | ``` 344 | 345 | Where: 346 | * **schema/**: Is the root folder of the Schema. It contains all the structure. 347 | * **types/**: Contains all the defined types. Each type goes in its own folder. 348 | * **type-name/**: Contains a type. The type is defined in the `index.js` file. 349 | * **interfaces/**: Contains the interfaces. Each interface goes in it's own file 350 | `interface-name.js`. 351 | 352 | In order for the queries to be automatically added to GraysQL, each type should define its queries 353 | in its own `query` key. 354 | 355 | LoadFromDir defines a new method in GraysQL: 356 | 357 | #### `GQL.load(directory, [overwrite])` #### 358 | > Load the objects from the given folder and add them to GraysQL. 359 | 360 | * **Parameters** 361 | * `directory` *String*: The root folder that contains the objects. 362 | * `Overwrite` *Boolean*: A flag wether the loaded objects should overwrite existent objects with 363 | the same name or not. 364 | 365 | ```javascript 366 | // schema/types/user.js 367 | module.exports = function (GQL) { 368 | return { 369 | name: 'User', 370 | fields: { 371 | id: { type: 'Int' }, 372 | nick: { type: 'String' } 373 | }, 374 | queries: { 375 | user: { 376 | type: 'User', 377 | args: { id: { type: 'Id' } }, 378 | resolve: (_, args) => GQL.options.DB.getUser(args.id) 379 | } 380 | } 381 | }; 382 | } 383 | 384 | // index.js 385 | const DB = require('./db'); 386 | const GraysQL = require('graysql'); 387 | const LoadFromDir = require('graysql/extensions/load-from-dir'); 388 | 389 | const GQL = new GraysQL({ DB: DB }); 390 | GQL.use(LoadFromDir); 391 | GQL.load('schema'); 392 | ``` 393 | 394 | ### Graylay ### 395 | 396 | Creates Relay compatible objects from your objects. Add needed entities for 397 | [Relay](https://facebook.github.io/relay/) to work with your Schema. For instance, it creates the 398 | Node interface or establishes connections between your types. Besides to the common keys your type 399 | need to define, Graylay adds one more, `nodeId`. Graylay will use this key to generate the 400 | [Node](https://github.com/graphql/graphql-relay-js#object-identification) interface needed by Relay. 401 | 402 | Additionaly, Graylay adds two new symbols to define relations between types. If you precede a type 403 | name with `@` Graylay will translate that into a 404 | [connection](https://github.com/graphql/graphql-relay-js#connections) with that type and will 405 | resolve to a [connectionFromArray](https://github.com/graphql/graphql-relay-js#connections). If you 406 | precede a type name with `@>` instead, Graylay will translate that into a connection that will 407 | resolve to a [connectionFromPromisedArray](https://github.com/graphql/graphql-relay-js#connections). 408 | In any case, you can specify your own resolve, and Graylay will honour it. Besides that, your types 409 | will need to define the usual `keys` needed by Relay like `isTypeOf` and implement the Node 410 | interface. 411 | 412 | ```javascript 413 | const GraysQL = require('graysql'); 414 | const DB = require('./db'); 415 | const GraphQLRelay = require('graphql-relay'); 416 | const Graylay = require('graysql/extensions/graylay'); 417 | 418 | const UserType = function (GQL) { 419 | return { 420 | name: 'User', 421 | nodeId: id => GQL.options.DB.getUser(id), 422 | isTypeOf: obj => obj instanceof GQL.options.DB.User, 423 | interfaces: ['Node'], 424 | fields: { 425 | id: { type: 'Int' }, 426 | nick: { type: 'String' }, 427 | groups: { 428 | type: '@Group' // Resolves to a connectionFromArray 429 | } 430 | } 431 | }; 432 | } 433 | 434 | const GQL = new GraysQL({ DB: DB }); 435 | GQL.use(Graylay); 436 | GQL.registerType(UserType); 437 | ``` 438 | 439 | ### Plugin API ### 440 | 441 | TODO 442 | 443 | ## Examples ## 444 | 445 | Usage examples can be found in [examples](examples) directory. 446 | 447 | ## Tests ## 448 | 449 | The tests are written with [mocha](https://mochajs.org/) and can be run with the following command: 450 | 451 | ```bash 452 | $ npm test 453 | ``` 454 | 455 | To get a code coverage report, run the following command: 456 | 457 | ```bash 458 | $ npm run cover 459 | ``` 460 | 461 | ## TODO ## 462 | 463 | - [x] Add support for non nullable args in mutations and queries. 464 | - [x] Implement Graylay and LoadFromDir. 465 | - [ ] Document Plugin API. 466 | - [ ] Provide an async version of LoadFromDir. 467 | - [x] Add support for lists as arguments in queries and mutations. 468 | 469 | ## License ## 470 | 471 | [MIT](LICENSE) 472 | -------------------------------------------------------------------------------- /examples/relay/db.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function Group(id, name) { 4 | this.id = id || groups.length; 5 | this.name = name; 6 | this.members = []; 7 | } 8 | 9 | 10 | function User(id, nick, group) { 11 | this.id = id || users.length; 12 | this.employeeId = nick + this.id; 13 | this.nick = nick; 14 | this.group = group; 15 | if (group) { 16 | group.members.push(this); 17 | } 18 | } 19 | 20 | 21 | const groups = [ 22 | new Group(1, 'Group 1'), 23 | new Group(2, 'Group 2') 24 | ]; 25 | 26 | 27 | const users = [ 28 | new User(1, 'Lars', groups[0]), 29 | new User(2, 'Deathvoid', groups[0]), 30 | new User(3, 'Grishan', groups[1]) 31 | ]; 32 | 33 | 34 | module.exports = { 35 | getUser: (id) => users.find(u => u.id === id), 36 | getGroup: (id) => groups.find(g => g.id === id), 37 | getUsers: () => users, 38 | getGroups: () => groups, 39 | createUser: (nick, group) => users[users.push(new User(null, nick, group)) - 1], 40 | createGroup: (name) => groups[groups.push(new Group(null, name)) - 1], 41 | User, 42 | Group 43 | }; 44 | -------------------------------------------------------------------------------- /examples/relay/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graysql-relay-example", 3 | "version": "1.0.0", 4 | "description": "GraysQL relay example.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/larsbs/graysql.git" 12 | }, 13 | "author": "Lorenzo Ruiz ", 14 | "license": "MIT", 15 | "dependencies": { 16 | "express": "^4.13.4", 17 | "express-graphql": "^0.4.5", 18 | "graphql": "^0.4.14", 19 | "graphql-relay": "^0.3.6", 20 | "graysql": "^0.3.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/relay/schema/interfaces/employee.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | name: 'Employee', 7 | fields: { 8 | employeeId: { type: 'String' } 9 | } 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /examples/relay/schema/types/group/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const GroupQueries = require('./queries'); 4 | const GroupMutations = require('./mutations'); 5 | 6 | 7 | module.exports = function (GQL) { 8 | return { 9 | name: 'Group', 10 | interfaces: ['Node'], 11 | nodeId: id => GQL.options.DB.getGroup(id), 12 | isTypeOf: obj => obj instanceof GQL.options.DB.Group, 13 | fields: { 14 | id: { type: 'Int' }, 15 | name: { type: 'String' }, 16 | members: { 17 | type: '@User', 18 | resolve: (group, args) => group.members 19 | } 20 | }, 21 | queries: { 22 | group: GroupQueries.group, 23 | groups: GroupQueries.groups 24 | }, 25 | mutations: { 26 | createGroup: GroupMutations.createGroup 27 | } 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /examples/relay/schema/types/group/mutations/create-group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'Group', 7 | args: { 8 | name: { type: 'String!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.createGroup(args.name) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/relay/schema/types/group/mutations/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | createGroup: require('./create-group') 3 | }; 4 | -------------------------------------------------------------------------------- /examples/relay/schema/types/group/queries/group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'Group', 7 | args: { 8 | id: { type: 'Int!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.getGroup(args.id) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/relay/schema/types/group/queries/groups.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'Group', 7 | resolve: () => GQL.options.DB.getGroups() 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /examples/relay/schema/types/group/queries/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | group: require('./group'), 3 | groups: require('./groups') 4 | }; 5 | -------------------------------------------------------------------------------- /examples/relay/schema/types/user/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const UserQueries = require('./queries'); 4 | const UserMutations = require('./mutations'); 5 | 6 | 7 | module.exports = function (GQL) { 8 | return { 9 | name: 'User', 10 | interfaces: ['Employee', 'Node'], 11 | nodeId: id => GQL.options.DB.getUser(id), 12 | isTypeOf: obj => obj instanceof GQL.options.DB.User, 13 | fields: { 14 | id: { type: 'Int' }, 15 | employeeId: { type: 'String' }, 16 | nick: { type: 'String' }, 17 | group: { type: 'Group' } 18 | }, 19 | queries: { 20 | user: UserQueries.user, 21 | users: UserQueries.users 22 | }, 23 | mutations: { 24 | createUser: UserMutations.createUser 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /examples/relay/schema/types/user/mutations/create-user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | args: { 8 | nick: { type: 'String!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.createUser(args.nick) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/relay/schema/types/user/mutations/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | createUser: require('./create-user') 3 | }; 4 | -------------------------------------------------------------------------------- /examples/relay/schema/types/user/queries/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | user: require('./user'), 3 | users: require('./users') 4 | }; 5 | -------------------------------------------------------------------------------- /examples/relay/schema/types/user/queries/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | args: { 8 | id: { type: 'Int!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.getUser(args.id) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/relay/schema/types/user/queries/users.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | resolve: () => GQL.options.DB.getUsers() 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /examples/relay/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const express = require('express'); 5 | const GraphQLUtils = require('graphql/utilities'); 6 | const GraphQLHTTP = require('express-graphql'); 7 | const GraysQL = require('graysql'); 8 | const LoadFromDir = require('graysql/extensions/load-from-dir'); 9 | const Graylay = require('graysql/extensions/graylay'); 10 | 11 | const DB = require('./db'); 12 | 13 | 14 | const DEFAULT_PORT = 3000; 15 | const SCHEMA_PATH = path.join(__dirname, 'schema'); 16 | 17 | 18 | const app = express(); 19 | const GQL = new GraysQL({ DB }); 20 | 21 | 22 | GQL.use(LoadFromDir); 23 | GQL.use(Graylay); 24 | 25 | 26 | GQL.load(SCHEMA_PATH); 27 | const Schema = GQL.generateSchema(); 28 | 29 | 30 | app.set('port', (process.env.port || DEFAULT_PORT)); 31 | 32 | 33 | app.use('/graphql', GraphQLHTTP({ 34 | schema: Schema, 35 | pretty: true, 36 | graphiql: true 37 | })); 38 | 39 | 40 | app.listen(app.get('port'), () => { 41 | console.log(`### Server started at: http://localhost:${app.get('port')}/`); 42 | console.log('### Using schema: '); 43 | console.log(GraphQLUtils.printSchema(Schema)) 44 | }); 45 | 46 | 47 | -------------------------------------------------------------------------------- /examples/simple/db.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function Group(id, name) { 4 | this.id = id || groups.length; 5 | this.name = name; 6 | this.members = []; 7 | } 8 | 9 | 10 | function User(id, nick, group) { 11 | this.id = id || users.length; 12 | this.employeeId = nick + this.id; 13 | this.nick = nick; 14 | this.group = group; 15 | if (group) { 16 | group.members.push(this); 17 | } 18 | } 19 | 20 | 21 | const groups = [ 22 | new Group(1, 'Group 1'), 23 | new Group(2, 'Group 2') 24 | ]; 25 | 26 | 27 | const users = [ 28 | new User(1, 'Lars', groups[0]), 29 | new User(2, 'Deathvoid', groups[0]), 30 | new User(3, 'Grishan', groups[1]) 31 | ]; 32 | 33 | 34 | module.exports = { 35 | getUser: (id) => users.find(u => u.id === id), 36 | getGroup: (id) => groups.find(g => g.id === id), 37 | getUsers: () => users, 38 | getGroups: () => groups, 39 | createUser: (nick, group) => users[users.push(new User(null, nick, group)) - 1], 40 | createGroup: (name) => groups[groups.push(new Group(null, name)) - 1], 41 | User, 42 | Group 43 | }; 44 | -------------------------------------------------------------------------------- /examples/simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graysql-simple-example", 3 | "version": "1.0.0", 4 | "description": "GraysQL simple example.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/larsbs/graysql.git" 12 | }, 13 | "author": "Lorenzo Ruiz ", 14 | "license": "MIT", 15 | "dependencies": { 16 | "express": "^4.13.4", 17 | "express-graphql": "^0.4.5", 18 | "graphql": "^0.4.14", 19 | "graphql-relay": "^0.3.6", 20 | "graysql": "^0.3.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/simple/schema/interfaces/employee.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | name: 'Employee', 7 | fields: { 8 | employeeId: { type: 'String' } 9 | } 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /examples/simple/schema/types/group/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const GroupQueries = require('./queries'); 4 | const GroupMutations = require('./mutations'); 5 | 6 | 7 | module.exports = function (GQL) { 8 | return { 9 | name: 'Group', 10 | isTypeOf: obj => obj instanceof GQL.options.DB.Group, 11 | fields: { 12 | id: { type: 'Int' }, 13 | name: { type: 'String' }, 14 | members: { type: '[User]' } 15 | }, 16 | queries: { 17 | group: GroupQueries.group, 18 | groups: GroupQueries.groups 19 | }, 20 | mutations: { 21 | createGroup: GroupMutations.createGroup 22 | } 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /examples/simple/schema/types/group/mutations/create-group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'Group', 7 | args: { 8 | name: { type: 'String!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.createGroup(args.name) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/simple/schema/types/group/mutations/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | createGroup: require('./create-group') 3 | }; 4 | -------------------------------------------------------------------------------- /examples/simple/schema/types/group/queries/group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'Group', 7 | args: { 8 | id: { type: 'Int!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.getGroup(args.id) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/simple/schema/types/group/queries/groups.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'Group', 7 | resolve: () => GQL.options.DB.getGroups() 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /examples/simple/schema/types/group/queries/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | group: require('./group'), 3 | groups: require('./groups') 4 | }; 5 | -------------------------------------------------------------------------------- /examples/simple/schema/types/user/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const UserQueries = require('./queries'); 4 | const UserMutations = require('./mutations'); 5 | 6 | 7 | module.exports = function (GQL) { 8 | return { 9 | name: 'User', 10 | interfaces: ['Employee'], 11 | isTypeOf: obj => obj instanceof GQL.options.DB.User, 12 | fields: { 13 | id: { type: 'Int' }, 14 | employeeId: { type: 'String' }, 15 | nick: { type: 'String' }, 16 | group: { type: 'Group' } 17 | }, 18 | queries: { 19 | user: UserQueries.user, 20 | users: UserQueries.users 21 | }, 22 | mutations: { 23 | createUser: UserMutations.createUser 24 | } 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /examples/simple/schema/types/user/mutations/create-user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | args: { 8 | nick: { type: 'String!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.createUser(args.nick) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/simple/schema/types/user/mutations/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | createUser: require('./create-user') 3 | }; 4 | -------------------------------------------------------------------------------- /examples/simple/schema/types/user/queries/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | user: require('./user'), 3 | users: require('./users') 4 | }; 5 | -------------------------------------------------------------------------------- /examples/simple/schema/types/user/queries/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | args: { 8 | id: { type: 'Int!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.getUser(args.id) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/simple/schema/types/user/queries/users.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | resolve: () => GQL.options.DB.getUsers() 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /examples/simple/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const express = require('express'); 5 | const GraphQLUtils = require('graphql/utilities'); 6 | const GraphQLHTTP = require('express-graphql'); 7 | const GraysQL = require('graysql'); 8 | const LoadFromDir = require('graysql/extensions/load-from-dir'); 9 | 10 | const DB = require('./db'); 11 | 12 | 13 | const DEFAULT_PORT = 3000; 14 | const SCHEMA_PATH = path.join(__dirname, 'schema'); 15 | 16 | 17 | const app = express(); 18 | const GQL = new GraysQL({ DB }); 19 | 20 | 21 | GQL.use(LoadFromDir); 22 | 23 | 24 | GQL.load(SCHEMA_PATH); 25 | const Schema = GQL.generateSchema(); 26 | 27 | 28 | app.set('port', (process.env.port || DEFAULT_PORT)); 29 | 30 | 31 | app.use('/graphql', GraphQLHTTP({ 32 | schema: Schema, 33 | pretty: true, 34 | graphiql: true 35 | })); 36 | 37 | 38 | app.listen(app.get('port'), () => { 39 | console.log(`### Server started at: http://localhost:${app.get('port')}/`); 40 | console.log('### Using schema: '); 41 | console.log(GraphQLUtils.printSchema(Schema)) 42 | }); 43 | 44 | 45 | -------------------------------------------------------------------------------- /extensions/graylay/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const GraphQLRelay = require('graphql-relay'); 4 | 5 | 6 | module.exports = function () { 7 | 8 | const nodes = {}; 9 | 10 | function isConnection(field) { 11 | return typeof field.type === 'string' && field.type.startsWith('@'); 12 | } 13 | 14 | function isPromisedConnection(field) { 15 | return isConnection(field) && field.type.startsWith('@>'); 16 | } 17 | 18 | function cleanFieldType(type) { 19 | return type.replace('@', '').replace('>', ''); 20 | } 21 | 22 | function implementsNodeInterface(type) { 23 | return !!type.interfaces().find(e => e.name === 'Node'); 24 | } 25 | 26 | return { 27 | 28 | onInit() { 29 | const nodeIface = GraphQLRelay.nodeDefinitions(globalId => { 30 | const node = GraphQLRelay.fromGlobalId(globalId); 31 | return nodes[node.type](node.id); 32 | }).nodeInterface; 33 | this.registerInterface(nodeIface); 34 | }, 35 | 36 | onParseTypeField(payload) { 37 | const type = payload.type; 38 | const field = payload.field; 39 | 40 | if (implementsNodeInterface(type) && payload.key === 'id') { 41 | return GraphQLRelay.globalIdField(type.name); 42 | } 43 | 44 | if (isConnection(field)) { 45 | return Object.assign({}, field, { 46 | type: GraphQLRelay.connectionDefinitions({ 47 | name: cleanFieldType(field.type), 48 | nodeType: payload.types[cleanFieldType(field.type)] 49 | }).connectionType, 50 | resolve: (root, args) => { 51 | if (isPromisedConnection(field)) { 52 | return GraphQLRelay.connectionFromPromisedArray(field.resolve(root, args), args); 53 | } 54 | else { 55 | return GraphQLRelay.connectionFromArray(field.resolve(root, args), args); 56 | } 57 | } 58 | }); 59 | } 60 | }, 61 | 62 | onGenerateType(payload) { 63 | const type = payload.type; 64 | 65 | if ( ! implementsNodeInterface(type)) { 66 | return type; 67 | } 68 | 69 | if ( ! type.nodeId) { 70 | throw new Error(`GraysQL Error: Type ${type.name} implements Node interface but doesn't provide a "nodeId" function`); 71 | } 72 | 73 | nodes[type.name] = type.nodeId; 74 | } 75 | 76 | }; 77 | 78 | }; 79 | -------------------------------------------------------------------------------- /extensions/load-from-dir/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | 6 | 7 | function _loadInterfaces(ifacesDir, overwrite) { 8 | try { 9 | fs.readdirSync(ifacesDir) 10 | .map(filename => require(`${ifacesDir}/${filename}`)) 11 | .map(iface => this.registerInterface(iface, overwrite)); 12 | } 13 | catch (err) { 14 | console.warn(`WARNING: No interfaces directory found at: ${ifacesDir}`); 15 | } 16 | } 17 | 18 | function _loadTypes(typesDir, overwrite) { 19 | try { 20 | fs.readdirSync(typesDir) 21 | .filter(filename => fs.statSync(path.join(typesDir, filename)).isDirectory()) 22 | .map(typeDir => require(`${typesDir}/${typeDir}`)) 23 | .map(type => this.registerType(type, overwrite)); 24 | } 25 | catch (err) { 26 | console.warn(`WARNING: No types directory found at: ${typesDir}`); 27 | } 28 | } 29 | 30 | module.exports = function () { 31 | return { 32 | 33 | load(directory, overwrite) { 34 | const ifacesDir = path.join(directory, 'interfaces'); 35 | const typesDir = path.join(directory, 'types'); 36 | 37 | _loadInterfaces.call(this, ifacesDir, overwrite); 38 | _loadTypes.call(this, typesDir, overwrite); 39 | } 40 | 41 | }; 42 | }; 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/graysql'); 2 | -------------------------------------------------------------------------------- /lib/graysql.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | 5 | const Type = require('./graysql/type'); 6 | const Query = require('./graysql/query'); 7 | const Mutation = require('./graysql/mutation'); 8 | const Interface = require('./graysql/interface'); 9 | 10 | 11 | class GraysQL { 12 | 13 | constructor(options) { 14 | if (options && typeof options !== 'object') { 15 | throw new TypeError(`GraysQL Error: Expected options to be an object, got ${typeof options} instead`); 16 | } 17 | 18 | // Initialize private state 19 | this._listeners = { 20 | onParseTypeField: [], 21 | onGenerateType: [], 22 | onParseInterfaceField: [], 23 | onGenerateInterface: [], 24 | onParseQueryArg: [], 25 | onGenerateQueryArg: [], 26 | onParseMutationArg: [], 27 | onGenerateMutationArg: [] 28 | }; 29 | this._types = {}; 30 | this._finalTypes = {}; 31 | this._interfaces = {}; 32 | this._finalInterfaces = {}; 33 | this._queries = {}; 34 | this._mutations = {}; 35 | 36 | // Initialize public state 37 | this.options = Object.assign({}, options); 38 | } 39 | 40 | use(extension) { 41 | if (typeof extension !== 'function') { 42 | throw new TypeError(`GraysQL Error: Expected extension to be a function, got ${typeof extension} instead`); 43 | } 44 | 45 | extension = extension(GraysQL); 46 | 47 | // Call onInit method of extension 48 | if (extension.onInit) { 49 | extension.onInit.bind(this)(); 50 | delete extension.onInit; 51 | } 52 | 53 | // Mount the extension 54 | for (const key in extension) { 55 | if ( ! this._listeners[key] && ! key.startsWith('_')) { 56 | GraysQL.prototype[key] = extension[key]; 57 | } 58 | else if (this._listeners[key]) { 59 | this._listeners[key].push(extension[key].bind(this)); 60 | } 61 | } 62 | } 63 | 64 | registerType(type, overwrite) { 65 | if (type instanceof graphql.GraphQLObjectType) { 66 | return this._finalTypes[type.name] = type; 67 | } 68 | 69 | if (typeof type !== 'function') { 70 | throw new TypeError(`GraysQL Error: Expected type to be a function, got ${typeof type} instead`); 71 | } 72 | 73 | const typeObj = type(this); 74 | 75 | if (this._types[typeObj.name] && ! overwrite) { 76 | throw new Error(`GraysQL Error: Type ${typeObj.name} is already registered`); 77 | } 78 | 79 | // Add type queries 80 | for (const queryName in typeObj.queries) { 81 | let query; 82 | if (typeof typeObj.queries[queryName] === 'function') { 83 | query = typeObj.queries[queryName]; 84 | } 85 | else { 86 | query = () => typeObj.queries[queryName]; 87 | } 88 | this.addQuery(queryName, query, overwrite); 89 | } 90 | // Add type mutations 91 | for (const mutationName in typeObj.mutations) { 92 | let mutation; 93 | if (typeof typeObj.mutations[mutationName] === 'function') { 94 | mutation = typeObj.mutations[mutationName]; 95 | } 96 | else { 97 | mutation = () => typeObj.mutations[mutationName]; 98 | } 99 | this.addMutation(mutationName, mutation, overwrite); 100 | } 101 | 102 | this._types[typeObj.name] = new Type(typeObj, { 103 | onParseTypeField: this._listeners.onParseTypeField, 104 | onGenerateType: this._listeners.onGenerateType 105 | }); 106 | 107 | return typeObj; 108 | } 109 | 110 | registerInterface(iface, overwrite) { 111 | if (iface instanceof graphql.GraphQLInterfaceType) { 112 | return this._finalInterfaces[iface.name] = iface; 113 | } 114 | 115 | if (typeof iface !== 'function') { 116 | throw new TypeError(`GraysQL Error: Expected interface to be a function, got ${typeof type} instead`); 117 | } 118 | 119 | const ifaceObj = iface(this); 120 | 121 | if (this._interfaces[ifaceObj.name] && ! overwrite) { 122 | throw new Error(`GraysQL Error: Interface ${ifaceObj.name} is already registered`); 123 | } 124 | 125 | this._interfaces[ifaceObj.name] = new Interface(ifaceObj, { 126 | onParseInterfaceField: this._listeners.onParseInterfaceField, 127 | onGenerateInterface: this._listeners.onGenerateInterface 128 | }); 129 | 130 | return ifaceObj; 131 | } 132 | 133 | addQuery(name, query, overwrite) { 134 | if (typeof query !== 'function') { 135 | throw new TypeError(`GraysQL Error: Expected query to be a function, got ${typeof query} instead`); 136 | } 137 | 138 | if ( ! name) { 139 | throw new Error(`GraysQL Error: Missing query name`); 140 | } 141 | 142 | const queryObj = query(this); 143 | 144 | if (this._queries[name] && ! overwrite) { 145 | throw new Error(`GraysQL Error: Query ${name} is already added`); 146 | } 147 | 148 | this._queries[name] = new Query(queryObj, { 149 | onGenerateQuery: this._listeners.onGenerateQuery, 150 | onParseQueryArg: this._listeners.onParseQueryArg 151 | }); 152 | 153 | return queryObj; 154 | } 155 | 156 | addMutation(name, mutation, overwrite) { 157 | if (typeof mutation !== 'function') { 158 | throw new TypeError(`GraysQL Error: Expected mutation to be a function, got ${typeof mutation} instead`); 159 | } 160 | 161 | if ( ! name) { 162 | throw new Error(`GraysQL Error: Missing mutation name`); 163 | } 164 | 165 | const mutationObj = mutation(this); 166 | 167 | if (this._mutations[name] && ! overwrite) { 168 | throw new Error(`GraysQL Error: Mutation ${name} is already added`); 169 | } 170 | 171 | this._mutations[name] = new Mutation(mutationObj); 172 | 173 | return mutationObj; 174 | } 175 | 176 | generateSchema() { 177 | const finalInterfaces = this._generateInterfaces(); 178 | const finalTypes = this._generateTypes(finalInterfaces); 179 | const Query = this._generateQuery(finalTypes); 180 | const Mutation = this._generateMutation(finalTypes); 181 | 182 | const schemaDef = {}; 183 | if (Query) { 184 | schemaDef['query'] = Query; 185 | } 186 | if (Mutation) { 187 | schemaDef['mutation'] = Mutation; 188 | } 189 | 190 | return new graphql.GraphQLSchema(schemaDef); 191 | } 192 | 193 | _generateInterfaces() { 194 | const finalInterfaces = Object.assign(this._finalInterfaces, this._interfaces); 195 | for (const key in this._interfaces) { 196 | finalInterfaces[key] = this._interfaces[key].generate({}); 197 | } 198 | return finalInterfaces; 199 | } 200 | 201 | _generateTypes(interfaces) { 202 | const finalTypes = Object.assign(this._finalTypes, this._types); 203 | for (const key in this._types) { 204 | finalTypes[key] = this._types[key].generate(finalTypes, interfaces); 205 | } 206 | return finalTypes; 207 | } 208 | 209 | _generateQuery(finalTypes) { 210 | const finalQueries = {}; 211 | for (const key in this._queries) { 212 | finalQueries[key] = this._queries[key].generate(finalTypes); 213 | } 214 | return Object.keys(finalQueries).length > 0 ? new graphql.GraphQLObjectType({ 215 | name: 'Query', 216 | fields: finalQueries 217 | }) : null; 218 | } 219 | 220 | _generateMutation(finalTypes) { 221 | const finalMutations = {}; 222 | for (const key in this._mutations) { 223 | finalMutations[key] = this._mutations[key].generate(finalTypes); 224 | } 225 | return Object.keys(finalMutations).length > 0 ? new graphql.GraphQLObjectType({ 226 | name: 'Mutation', 227 | fields: finalMutations 228 | }) : null; 229 | } 230 | 231 | } 232 | 233 | 234 | module.exports = GraysQL; 235 | -------------------------------------------------------------------------------- /lib/graysql/interface.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | const Utils = require('../utils'); 5 | 6 | 7 | class Interface { 8 | 9 | constructor(rawInterface, listeners) { 10 | if (typeof rawInterface !== 'object' || Array.isArray(rawInterface)) { 11 | throw new TypeError(`GraysQL Error: Expected rawInterface to be an object, got ${typeof rawInterface} instead`); 12 | } 13 | 14 | // Initialize private state 15 | this._rawInterface = rawInterface; 16 | 17 | listeners = listeners || {}; 18 | this._listeners = { 19 | onGenerateInterface: listeners.onGenerateInterface || [], 20 | onParseInterfaceField: listeners.onParseInterfaceField || [] 21 | }; 22 | } 23 | 24 | generate(types) { 25 | let ifaceDef = Object.assign({}, this._rawInterface, { 26 | fields: () => this._parseFields(this._rawInterface.fields, types) 27 | }); 28 | for (const listener of this._listeners.onGenerateInterface) { 29 | ifaceDef = Object.assign(ifaceDef, listener({ iface: ifaceDef, types })); 30 | } 31 | return new graphql.GraphQLInterfaceType(ifaceDef); 32 | } 33 | 34 | _parseFields(fields, types) { 35 | const finalFields = {}; 36 | for (const key in fields) { 37 | finalFields[key] = this._parseField(key, fields[key], types); 38 | } 39 | return finalFields; 40 | } 41 | 42 | _parseField(key, field, types) { 43 | let finalField = Object.assign({}, field); 44 | for (const listener of this._listeners.onParseInterfaceField) { 45 | finalField = Object.assign(finalField, listener({ key, field, types })); 46 | } 47 | return Object.assign({}, finalField, { 48 | type: Utils.parseType(finalField.type, types) 49 | }); 50 | } 51 | 52 | } 53 | 54 | module.exports = Interface; 55 | -------------------------------------------------------------------------------- /lib/graysql/mutation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Utils = require('../utils'); 4 | 5 | 6 | class Mutation { 7 | 8 | constructor(rawMutation, listeners) { 9 | if (typeof rawMutation !== 'object' || Array.isArray(rawMutation)) { 10 | throw new TypeError(`GraysQL Error: Expected rawMutation to be an object, got ${typeof rawMutation} instead`); 11 | } 12 | 13 | // Initialize private state 14 | listeners = listeners || {}; 15 | this._listeners = { 16 | onParseMutationArg: listeners.onParseMutationArg || [], 17 | onGenerateMutation: listeners.onGenerateMutation || [] 18 | }; 19 | this._rawMutation = rawMutation; 20 | } 21 | 22 | generate(types) { 23 | let mutationDef = Object.assign({}, this._rawMutation, { 24 | type: types[this._rawMutation.type], 25 | args: this._parseArgs(this._rawMutation.args) 26 | }); 27 | for (const listener of this._listeners.onGenerateMutation) { 28 | mutationDef = Object.assign(mutationDef, listener({ mutation: mutationDef })); 29 | } 30 | return mutationDef; 31 | } 32 | 33 | _parseArgs(args) { 34 | const finalArgs = {}; 35 | for (const key in args) { 36 | finalArgs[key] = this._parseArg(key, args[key]); 37 | } 38 | return finalArgs; 39 | } 40 | 41 | _parseArg(key, arg) { 42 | let finalArg = Object.assign({}, arg); 43 | for (const listener of this._listeners.onParseMutationArg) { 44 | finalArg = Object.assign(finalArg, listener({ key, arg })); 45 | } 46 | return Object.assign({}, finalArg, { 47 | type: Utils.parseType(finalArg.type) 48 | }); 49 | } 50 | 51 | } 52 | 53 | module.exports = Mutation; 54 | -------------------------------------------------------------------------------- /lib/graysql/query.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Utils = require('../utils'); 4 | 5 | 6 | class Query { 7 | 8 | constructor(rawQuery, listeners) { 9 | if (typeof rawQuery !== 'object' || Array.isArray(rawQuery)) { 10 | throw new TypeError(`GraysQL Error: Expected rawQuery to be an object, got ${typeof rawQuery} instead`); 11 | } 12 | 13 | // Initialize private state 14 | listeners = listeners || {}; 15 | this._listeners = { 16 | onParseQueryArg: listeners.onParseQueryArg || [], 17 | onGenerateQuery: listeners.onGenerateQuery || [] 18 | }; 19 | this._rawQuery = rawQuery; 20 | } 21 | 22 | generate(types) { 23 | let queryDef = Object.assign({}, this._rawQuery, { 24 | type: Utils.parseType(this._rawQuery.type, types), 25 | args: this._parseArgs(this._rawQuery.args) 26 | }); 27 | for (const listener of this._listeners.onGenerateQuery) { 28 | queryDef = Object.assign(queryDef, listener({ query: queryDef })); 29 | } 30 | return queryDef; 31 | } 32 | 33 | _parseArgs(args) { 34 | const finalArgs = {}; 35 | for (const key in args) { 36 | finalArgs[key] = this._parseArg(key, args[key]); 37 | } 38 | return finalArgs; 39 | } 40 | 41 | _parseArg(key, arg) { 42 | let finalArg = Object.assign({}, arg); 43 | for (const listener of this._listeners.onParseQueryArg) { 44 | finalArg = Object.assign(finalArg, listener({ key, arg })); 45 | } 46 | return Object.assign({}, finalArg, { 47 | type: Utils.parseType(finalArg.type) 48 | }); 49 | } 50 | 51 | } 52 | 53 | module.exports = Query; 54 | -------------------------------------------------------------------------------- /lib/graysql/type.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | const Utils = require('../utils'); 5 | 6 | 7 | class Type { 8 | 9 | constructor(rawType, listeners) { 10 | if (typeof rawType !== 'object' || Array.isArray(rawType)) { 11 | throw new TypeError(`GraysQL Error: Expected rawType to be an object, got ${typeof rawType} instead`); 12 | } 13 | 14 | // Initialize private state 15 | this._rawType = rawType; 16 | 17 | listeners = listeners || {}; 18 | this._listeners = { 19 | onGenerateType: listeners.onGenerateType || [], 20 | onParseTypeField: listeners.onParseTypeField || [], 21 | onParseQueryArg: listeners.onParseQueryArg || [], 22 | }; 23 | } 24 | 25 | generate(types, interfaces) { 26 | let typeDef = Object.assign({}, this._rawType, { 27 | interfaces: () => this._rawType.interfaces ? this._rawType.interfaces.map(iface => interfaces[iface]) : [], 28 | fields: () => this._parseFields(this._rawType.fields, typeDef, types, interfaces) 29 | }); 30 | for (const listener of this._listeners.onGenerateType) { 31 | typeDef = Object.assign(typeDef, listener({ type: typeDef, types, interfaces })); 32 | } 33 | return new graphql.GraphQLObjectType(typeDef); 34 | } 35 | 36 | _parseFields(fields, type, types, interfaces) { 37 | const finalFields = {}; 38 | for (const key in fields) { 39 | finalFields[key] = this._parseField(key, fields[key], type, types, interfaces); 40 | } 41 | return finalFields; 42 | } 43 | 44 | _parseField(key, field, type, types) { 45 | let finalField = Object.assign({}, field); 46 | for (const listener of this._listeners.onParseTypeField) { 47 | finalField = Object.assign(finalField, listener({ key, field, type, types })); 48 | } 49 | return Object.assign({}, finalField, { 50 | type: Utils.parseType(finalField.type, types), 51 | args: this._parseArgs(field.args), 52 | }); 53 | } 54 | 55 | _parseArgs(args) { 56 | const finalArgs = {}; 57 | for (const key in args) { 58 | finalArgs[key] = this._parseArg(key, args[key]); 59 | } 60 | return finalArgs; 61 | } 62 | 63 | _parseArg(key, arg) { 64 | let finalArg = Object.assign({}, arg); 65 | for (const listener of this._listeners.onParseQueryArg) { 66 | finalArg = Object.assign(finalArg, listener({ key, arg })); 67 | } 68 | return Object.assign({}, finalArg, { 69 | type: Utils.parseType(finalArg.type) 70 | }); 71 | } 72 | 73 | } 74 | 75 | module.exports = Type; 76 | -------------------------------------------------------------------------------- /lib/utils/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const TypeParser = require('./type-parser'); 4 | 5 | 6 | module.exports = { 7 | 8 | parseType: TypeParser.parseType, 9 | 10 | bindAll(listeners, thisArg) { 11 | return listeners.map(l => l.bind(thisArg)); 12 | } 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /lib/utils/type-parser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | 5 | 6 | function parseType(type, dependencies) { 7 | if (typeof type !== 'string') { 8 | return type; // We cannot parse a non string type 9 | } 10 | if (type.endsWith('!')) { 11 | return parseNonNullType(type, dependencies, parseType); 12 | } 13 | if (type.startsWith('[')) { 14 | return parseArrayType(type, dependencies, parseType); 15 | } 16 | 17 | return parseSimpleType(type, dependencies) || type; 18 | } 19 | 20 | function parseSimpleType(type, dependencies) { 21 | dependencies = dependencies || {}; 22 | switch (type) { 23 | case 'Int': 24 | return graphql.GraphQLInt; 25 | case 'String': 26 | return graphql.GraphQLString; 27 | case 'Date': 28 | return graphql.GraphQLString; 29 | default: 30 | return dependencies[type]; 31 | } 32 | } 33 | 34 | function parseNonNullType(type, dependencies, next) { 35 | const cleanedType = type.replace('!', ''); 36 | return new graphql.GraphQLNonNull(next(cleanedType, dependencies)); 37 | } 38 | 39 | function parseArrayType(type, dependencies, next) { 40 | const cleanedType = type.replace('[', '').replace(']', ''); 41 | return new graphql.GraphQLList(next(cleanedType, dependencies)); 42 | } 43 | 44 | 45 | module.exports = { 46 | parseType 47 | }; 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graysql", 3 | "version": "0.5.0", 4 | "description": "GraysQL is a GraphQL manager and loader.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm run lint && mocha --check-leaks -t 5000 test/index.js", 8 | "cover": "npm run lint && istanbul cover _mocha -- --check-leaks -t 5000 -b -R spec test/index.js", 9 | "lint": "eslint index.js lib/" 10 | }, 11 | "keywords": [ 12 | "graphql" 13 | ], 14 | "author": "Lorenzo Ruiz ", 15 | "license": "MIT", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/larsbs/graysql.git" 19 | }, 20 | "peerDependencies": { 21 | "graphql": "^0.8.2", 22 | "graphql-relay": "^0.4.3" 23 | }, 24 | "devDependencies": { 25 | "chai": "^3.4.1", 26 | "eslint": "^1.10.3", 27 | "graphql": "^0.8.2", 28 | "graphql-relay": "^0.4.3", 29 | "istanbul": "^0.4.2", 30 | "mocha": "^2.3.4" 31 | }, 32 | "dependencies": {} 33 | } 34 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | const GraysQL = require('../lib/graysql'); 2 | const Type = require('../lib/graysql/type'); 3 | const Interface = require('../lib/graysql/interface'); 4 | const Query = require('../lib/graysql/query'); 5 | const Mutation = require('../lib/graysql/mutation'); 6 | const LoadFromDir = require('../extensions/load-from-dir'); 7 | const Graylay = require('../extensions/graylay'); 8 | const Utils = require('../lib/utils'); 9 | const TypeParser = require('../lib/utils/type-parser'); 10 | 11 | 12 | describe('UNIT TESTS', function () { 13 | describe('GraysQL', function () { 14 | require('./unit/graysql/type')(Type); 15 | require('./unit/graysql/interface')(Interface); 16 | require('./unit/graysql/query')(Query); 17 | require('./unit/graysql/mutation')(Mutation); 18 | require('./unit/graysql')(GraysQL); 19 | describe('@Utils', function () { 20 | require('./unit/utils')(Utils); 21 | require('./unit/utils/type-parser')(TypeParser); 22 | }); 23 | describe('@Extensions', function () { 24 | require('./unit/extensions/load-from-dir')(GraysQL, LoadFromDir); 25 | require('./unit/extensions/graylay')(GraysQL, Graylay); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/support/db.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function Group(id, name) { 4 | this.id = id; 5 | this.name = name; 6 | this.members = []; 7 | } 8 | 9 | 10 | function User(id, nick, group) { 11 | this.id = id; 12 | this.nick = nick; 13 | this.group = group; 14 | group.members.push(this); 15 | } 16 | 17 | 18 | const groups = [ 19 | new Group(1, 'Group 1'), 20 | new Group(2, 'Group 2') 21 | ]; 22 | 23 | 24 | const users = [ 25 | new User(1, 'Lars', groups[0]), 26 | new User(2, 'Deathvoid', groups[0]), 27 | new User(3, 'Grishan', groups[1]) 28 | ]; 29 | 30 | 31 | module.exports = { 32 | getUser: (id) => users.find(u => u.id === id), 33 | getGroup: (id) => groups.find(g => g.id === id), 34 | User, 35 | Group 36 | }; 37 | -------------------------------------------------------------------------------- /test/support/extensions/test-extension.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (GraysQL) { 4 | return { 5 | onInit() { 6 | if (this && this.options && this.options.increaseOnInit) { 7 | this.options.increaseOnInit += 1; 8 | } 9 | }, 10 | customMethod() { 11 | return GraysQL; 12 | }, 13 | onParseTypeField(payload) { 14 | if (this && this.options && this.options.increaseOnParseTypeField) { 15 | this.options.increaseOnParseTypeField += 1; 16 | } 17 | }, 18 | onGenerateType(payload) { 19 | if (this && this.options && this.options.increaseOnGenerateType) { 20 | this.options.increaseOnGenerateType += 1; 21 | } 22 | } 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/interfaces/employee.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | name: 'Employee', 7 | fields: { 8 | employeeId: { 9 | type: 'String' 10 | } 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/relay-types/group/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (GQL) { 4 | return { 5 | name: 'Group', 6 | interfaces: ['Node'], 7 | nodeId: id => GQL.options.DB.getGroup(id), 8 | isTypeOf: obj => obj instanceof GQL.options.DB.Group, 9 | fields: { 10 | id: { type: 'Int' }, 11 | name: { type: 'String' }, 12 | members: { 13 | type: '@User', 14 | resolve: (group, args) => group.members 15 | } 16 | }, 17 | queries: { 18 | group: require('./queries/group') 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/relay-types/group/queries/group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'Group', 7 | args: { 8 | id: { type: 'Int' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.getGroup(args.id) 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/relay-types/user/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (GQL) { 4 | return { 5 | name: 'User', 6 | interfaces: ['Node'], 7 | nodeId: id => GQL.options.DB.getUser(id), 8 | isTypeOf: obj => obj instanceof GQL.options.DB.User, 9 | fields: { 10 | id: { type: 'Int' }, 11 | nick: { type: 'String' }, 12 | group: { type: 'Group' } 13 | }, 14 | queries: { 15 | user: require('./queries/user') 16 | } 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/relay-types/user/queries/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | args: { 8 | id: { type: 'Int!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.getUser(args.id) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/types/group/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (GQL) { 4 | return { 5 | name: 'Group', 6 | fields: { 7 | id: { type: 'Int' }, 8 | name: { type: 'String' }, 9 | members: { type: '[User]' } 10 | }, 11 | queries: { 12 | group: require('./queries/group') 13 | } 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/types/group/queries/group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'Group', 7 | args: { 8 | id: { type: 'Int' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.getGroup(args.id) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/types/user/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (GQL) { 4 | return { 5 | name: 'User', 6 | interfaces: ['Employee'], 7 | isTypeOf: obj => obj instanceof GQL.options.DB.User, 8 | fields: { 9 | id: { type: 'Int' }, 10 | employeeId: { type: 'String' }, 11 | nick: { type: 'String' }, 12 | group: { type: 'Group' } 13 | }, 14 | queries: { 15 | user: require('./queries/user') 16 | }, 17 | mutations: { 18 | createUser: require('./mutations/create-user') 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/types/user/mutations/create-user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | args: { 8 | nick: { type: 'String!' } 9 | }, 10 | resolve: (_, args) => ({ id: 5, nick: args.nick }) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /test/support/test-schema-dir/types/user/queries/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | type: 'User', 7 | args: { 8 | id: { type: 'Int!' } 9 | }, 10 | resolve: (_, args) => GQL.options.DB.getUser(args.id) 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /test/support/test-schema-relay.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | const GraphQLRelay = require('graphql-relay'); 5 | const DB = require('./db'); 6 | 7 | 8 | const NodeInterface = GraphQLRelay.nodeDefinitions(globalId => { 9 | const node = GraphQLRelay.fromGlobalId(globalId); 10 | switch(node.type) { 11 | case 'User': 12 | return DB.getUser(node.id); 13 | case 'Group': 14 | return DB.getGroup(node.id); 15 | default: 16 | return null; 17 | } 18 | }).nodeInterface; 19 | 20 | 21 | const User = new graphql.GraphQLObjectType({ 22 | name: 'User', 23 | interfaces: [NodeInterface], 24 | isTypeOf: obj => obj instanceof DB.User, 25 | fields: () => ({ 26 | id: GraphQLRelay.globalIdField('User'), 27 | nick: { type: graphql.GraphQLString }, 28 | group: { type: Group } 29 | }) 30 | }); 31 | 32 | 33 | const Group = new graphql.GraphQLObjectType({ 34 | name: 'Group', 35 | interfaces: [NodeInterface], 36 | isTypeOf: obj => obj instanceof DB.Group, 37 | fields: () => ({ 38 | id: GraphQLRelay.globalIdField('Group'), 39 | name: { type: graphql.GraphQLString }, 40 | members: { 41 | type: GraphQLRelay.connectionDefinitions({ 42 | name: 'User', 43 | nodeType: User 44 | }).connectionType, 45 | resolve: (group, args) => GraphQLRelay.connectionFromArray(group.members, args) 46 | } 47 | }) 48 | }); 49 | 50 | 51 | const Query = new graphql.GraphQLObjectType({ 52 | name: 'Query', 53 | fields: () => ({ 54 | group: { 55 | type: Group, 56 | args: { 57 | id: { type: graphql.GraphQLInt } 58 | }, 59 | resolve: (_, args) => DB.getGroup(args.id) 60 | }, 61 | user: { 62 | type: User, 63 | args: { 64 | id: { type: new graphql.GraphQLNonNull(graphql.GraphQLInt) } 65 | }, 66 | resolve: (_, args) => DB.getUser(args.id) 67 | } 68 | }) 69 | }); 70 | 71 | 72 | const Schema = new graphql.GraphQLSchema({ 73 | query: Query 74 | }); 75 | 76 | 77 | module.exports = { 78 | User, 79 | Group, 80 | Query, 81 | Schema 82 | }; 83 | -------------------------------------------------------------------------------- /test/support/test-schema.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | const DB = require('./db'); 5 | 6 | 7 | const Employee = new graphql.GraphQLInterfaceType({ 8 | name: 'Employee', 9 | fields: () => ({ 10 | employeeId: { type: graphql.GraphQLString } 11 | }) 12 | }); 13 | 14 | 15 | const User = new graphql.GraphQLObjectType({ 16 | name: 'User', 17 | interfaces: () => [Employee], 18 | isTypeOf: obj => obj instanceof DB.User, 19 | fields: () => ({ 20 | id: { type: graphql.GraphQLInt }, 21 | employeeId: { type: graphql.GraphQLString }, 22 | nick: { type: graphql.GraphQLString }, 23 | group: { type: Group } 24 | }) 25 | }); 26 | 27 | 28 | const Group = new graphql.GraphQLObjectType({ 29 | name: 'Group', 30 | fields: () => ({ 31 | id: { type: graphql.GraphQLInt }, 32 | name: { type: graphql.GraphQLString }, 33 | members: { type: new graphql.GraphQLList(User) } 34 | }) 35 | }); 36 | 37 | 38 | const Query = new graphql.GraphQLObjectType({ 39 | name: 'Query', 40 | fields: () => ({ 41 | group: { 42 | type: Group, 43 | args: { 44 | id: { type: graphql.GraphQLInt } 45 | }, 46 | resolve: (_, args) => DB.getGroup(args.id) 47 | }, 48 | user: { 49 | type: User, 50 | args: { 51 | id: { type: new graphql.GraphQLNonNull(graphql.GraphQLInt) } 52 | }, 53 | resolve: (_, args) => DB.getUser(args.id) 54 | } 55 | }) 56 | }); 57 | 58 | 59 | const Mutation = new graphql.GraphQLObjectType({ 60 | name: 'Mutation', 61 | fields: () => ({ 62 | createUser: { 63 | type: User, 64 | args: { 65 | nick: { type: new graphql.GraphQLNonNull(graphql.GraphQLString) } 66 | }, 67 | resolve: (_, args) => ({ id: 5, nick: args.nick }) 68 | } 69 | }) 70 | }); 71 | 72 | 73 | const Schema = new graphql.GraphQLSchema({ 74 | query: Query, 75 | mutation: Mutation 76 | }); 77 | 78 | 79 | module.exports = { 80 | User, 81 | Group, 82 | Query, 83 | Schema 84 | }; 85 | -------------------------------------------------------------------------------- /test/support/types/group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const DB = require('../db'); 4 | 5 | 6 | module.exports = function (GQL) { 7 | return { 8 | name: 'Group', 9 | fields: { 10 | id: { type: 'Int' }, 11 | name: { type: 'String' }, 12 | members: { type: '[User]' } 13 | }, 14 | queries: { 15 | group: { 16 | type: 'Group', 17 | args: { 18 | id: { type: 'Int' } 19 | }, 20 | resolve: (_, args) => DB.getGroup(args.id) 21 | } 22 | } 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /test/support/types/simple.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = function (GQL) { 5 | return { 6 | name: 'Simple', 7 | fields: { 8 | id: { type: 'Int' } 9 | }, 10 | queries: { 11 | simple: { 12 | type: 'Simple', 13 | args: { 14 | id: { type: 'Int' } 15 | }, 16 | resolve: (_, args) => { id: 1} 17 | } 18 | }, 19 | mutations: { 20 | createSimple: { 21 | type: 'Simple', 22 | args: { 23 | id: { type: 'Int' } 24 | }, 25 | resolve: (_, args) => { id: args.id } 26 | } 27 | } 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /test/support/types/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const DB = require('../db'); 4 | 5 | 6 | module.exports = function (GQL) { 7 | return { 8 | name: 'User', 9 | fields: { 10 | id: { type: 'Int' }, 11 | nick: { type: 'String' }, 12 | group: { type: 'Group' }, 13 | dummy: { 14 | type: 'String', 15 | args: { 16 | id: { type: 'String' }, 17 | }, 18 | resolve: () => 'Hello dummy!', 19 | }, 20 | }, 21 | queries: { 22 | user: { 23 | type: 'User', 24 | args: { 25 | id: { type: 'Int!' } 26 | }, 27 | resolve: (_, args) => DB.getUser(args.id) 28 | } 29 | }, 30 | mutations: { 31 | createUser: { 32 | type: 'User', 33 | args: { 34 | nick: { type: 'String!' }, 35 | }, 36 | resolve: (_, args) => ({ 37 | id: 5, 38 | nick: args.nick 39 | }) 40 | } 41 | } 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /test/unit/extensions/graylay/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const expect = require('chai').expect; 4 | const graphql = require('graphql'); 5 | const GraphQLUtils = require('graphql/utilities'); 6 | 7 | const DB = require('../../../support/db'); 8 | const TestUser = require('../../../support/test-schema-dir/relay-types/user'); 9 | const TestGroup = require('../../../support/test-schema-dir/relay-types/group'); 10 | const TestSchemaRelay = require('../../../support/test-schema-relay'); 11 | 12 | 13 | module.exports = function (GraysQL, Graylay) { 14 | 15 | describe('@Graylay', function () { 16 | 17 | let GQL; 18 | let Schema; 19 | 20 | before(function () { 21 | GQL = new GraysQL({ DB }); 22 | GQL.use(Graylay); 23 | GQL.registerType(TestGroup); 24 | GQL.registerType(TestUser); 25 | Schema = GQL.generateSchema(); 26 | }); 27 | 28 | it('should generate a Relay schema', function () { 29 | const result = GraphQLUtils.printSchema(Schema); 30 | const expected = GraphQLUtils.printSchema(TestSchemaRelay.Schema); 31 | expect(result).to.equal(expected); 32 | }); 33 | 34 | it('should generate a valid Relay schema', function (done) { 35 | const query = `query GetGroup { 36 | group(id: 1) { 37 | id, 38 | name, 39 | members { 40 | edges { 41 | node { 42 | id, 43 | nick 44 | } 45 | } 46 | } 47 | } 48 | }`; 49 | const expected = { 50 | "data": { 51 | "group": { 52 | "id": "R3JvdXA6MQ==", 53 | "name": "Group 1", 54 | "members": { 55 | "edges": [ 56 | { 57 | "node": { 58 | "id": "VXNlcjox", 59 | "nick": "Lars" 60 | } 61 | }, 62 | { 63 | "node": { 64 | "id": "VXNlcjoy", 65 | "nick": "Deathvoid" 66 | } 67 | } 68 | ] 69 | } 70 | } 71 | } 72 | } 73 | graphql.graphql(Schema, query) 74 | .then(result => { 75 | expect(result).to.deep.equal(expected); 76 | done(); 77 | }) 78 | .catch(err => done(err)); 79 | }); 80 | 81 | }); 82 | 83 | }; 84 | -------------------------------------------------------------------------------- /test/unit/extensions/load-from-dir/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const expect = require('chai').expect; 5 | const GraphQLUtils = require('graphql/utilities'); 6 | 7 | const DB = require('../../../support/db'); 8 | const TestSchema = require('../../../support/test-schema'); 9 | const TestUser = require('../../../support/test-schema-dir/types/user'); 10 | 11 | 12 | module.exports = function (GraysQL, LoadFromDir) { 13 | 14 | describe('@LoadFromDir', function () { 15 | 16 | let GQL; 17 | const schemaDir = path.resolve(__dirname, '../../../support/test-schema-dir'); 18 | 19 | beforeEach(function () { 20 | GQL = new GraysQL({ DB }); 21 | GQL.use(LoadFromDir); 22 | }); 23 | 24 | describe('#load(directory, [overwrite])', function () { 25 | it('should load the schema from the directory', function () { 26 | GQL.load(schemaDir); 27 | const result = GraphQLUtils.printSchema(GQL.generateSchema()); 28 | const expected = GraphQLUtils.printSchema(TestSchema.Schema); 29 | expect(result).to.equal(expected); 30 | }); 31 | it.skip('should not overwrite by default the registered objects in GraysQL', function () { 32 | GQL.registerType(TestUser); 33 | expect(() => GQL.load(schemaDir)).to.throw(Error, /GraysQL Error: Type/); 34 | }); 35 | it('should overwrite the registered objects in GraysQL if specified', function () { 36 | GQL.registerType(TestUser); 37 | expect(() => GQL.load(schemaDir, true)).to.not.throw(Error, /GraysQL Error: Type/); 38 | }); 39 | }); 40 | 41 | }); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/unit/graysql.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const expect = require('chai').expect; 4 | const graphql = require('graphql'); 5 | const GraphQLUtils = require('graphql/utilities'); 6 | 7 | const DB = require('../support/db'); 8 | const TestExtension = require('../support/extensions/test-extension'); 9 | const TestUser = require('../support/test-schema-dir/types/user'); 10 | const TestGroup = require('../support/test-schema-dir/types/group'); 11 | const SimpleType = require('../support/types/simple'); 12 | const TestEmployee = require('../support/test-schema-dir/interfaces/employee'); 13 | const TestSchema = require('../support/test-schema'); 14 | 15 | 16 | module.exports = function (GraysQL) { 17 | 18 | describe('@GraysQL', function () { 19 | 20 | describe('#constructor([options])', function () { 21 | it('should only accepts an object as options', function () { 22 | expect(() => new GraysQL('asdf')).to.throw(TypeError, /GraysQL Error/); 23 | }); 24 | it('should put received options in the options property', function () { 25 | const GQL = new GraysQL({ test: 'testOption' }); 26 | expect(GQL.options).to.contain.key('test'); 27 | }); 28 | }); 29 | 30 | describe('#use(extension)', function () { 31 | const GQL = new GraysQL({ increaseOnInit: 1 }); 32 | before(function () { 33 | GQL.use(TestExtension); 34 | }); 35 | it('should only accept functions', function () { 36 | expect(GQL.use.bind(GraysQL, 'asdf')).to.throw(TypeError, /GraysQL Error/); 37 | }); 38 | it('should call onInit method in the extension', function () { 39 | expect(GQL.options.increaseOnInit).to.be.greaterThan(1); 40 | }); 41 | it('should merge non listeners with the prototype', function () { 42 | expect(GraysQL.prototype).to.contain.key('customMethod'); 43 | }); 44 | it('should not merge private methods (prefixed with _) with the prototype'); 45 | it('should pass GraysQL to the extensions', function () { 46 | expect(GQL.customMethod()).to.equal(GraysQL); 47 | }); 48 | it('should not merge listeners with the prototype', function () { 49 | expect(GraysQL.prototype).to.not.contain.key('onInit'); 50 | }); 51 | }); 52 | 53 | describe('#registerType(type, [overwrite])', function () { 54 | let GQL; 55 | before(function () { 56 | GQL = new GraysQL(); 57 | }); 58 | it('should only register functions', function () { 59 | expect(GQL.registerType.bind(GQL, 'asdfa')).to.throw(TypeError, /GraysQL Error: Expected type to be a function/); 60 | }); 61 | it('should not overwrite a type by default', function () { 62 | GQL.registerType(TestUser); 63 | expect(GQL.registerType.bind(GQL, TestUser)).to.throw(Error, /GraysQL Error: Type /); 64 | }); 65 | it('should allow to overwrite types when specified', function () { 66 | expect(GQL.registerType.bind(GQL, TestUser, true)).to.not.throw(Error, /GraysQL Error: Type /); 67 | }); 68 | it('should return the registered type', function () { 69 | const returnedType = GQL.registerType(TestGroup); 70 | const type = TestGroup(GQL); 71 | expect(JSON.stringify(returnedType)).to.equal(JSON.stringify(type)); 72 | }); 73 | }); 74 | 75 | describe('#registerInterface(interface, [overwrite])', function () { 76 | let GQL; 77 | beforeEach(function () { 78 | GQL = new GraysQL(); 79 | }); 80 | it('should only register functions', function () { 81 | expect(GQL.registerInterface.bind(GQL, 'asdf')).to.throw(TypeError, /GraysQL Error: Expected interface to be a function/) 82 | }); 83 | it('should not overwrite an interface by default', function () { 84 | GQL.registerInterface(TestEmployee); 85 | expect(GQL.registerInterface.bind(GQL, TestEmployee)).to.throw(Error, /GraysQL Error: Interface/); 86 | }); 87 | it('should allow to overwrite interfaces when specified', function () { 88 | expect(GQL.registerInterface.bind(GQL, TestEmployee, true)).to.not.throw(Error, /GraysQL Error: Interface/); 89 | }); 90 | it('should return the registered interface', function () { 91 | const returnedInterface = GQL.registerInterface(TestEmployee); 92 | const iface = TestEmployee(GQL); 93 | expect(JSON.stringify(returnedInterface)).to.equal(JSON.stringify(iface)); 94 | }); 95 | }); 96 | 97 | describe('#addQuery(name, query, [overwrite])', function () { 98 | let GQL; 99 | beforeEach(function () { 100 | GQL = new GraysQL(); 101 | }); 102 | it('should only add functions', function () { 103 | expect(GQL.addQuery.bind(GQL, 'adfs', 'asdfa')).to.throw(TypeError, /GraysQL Error: Expected query to be a function/); 104 | expect(GQL.addQuery.bind(GQL, 'adfs', x => x)).to.not.throw(TypeError, /GraysQL Error: Expected query to be a function/); 105 | }); 106 | it('should not add a query with an undefined name', function () { 107 | const user = (GQL) => TestUser().queries.user; 108 | expect(GQL.addQuery.bind(GQL, null, user)).to.throw(Error, /GraysQL Error: Missing query name/); 109 | expect(GQL.addQuery.bind(GQL, undefined, user)).to.throw(Error, /GraysQL Error: Missing query name/); 110 | expect(GQL.addQuery.bind(GQL, '', user)).to.throw(Error, /GraysQL Error: Missing query name/); 111 | }); 112 | it('should not ovewrite a query by default', function () { 113 | const q = (GQL) => ({ 114 | type: 'Simple', 115 | args: { id: { type: 'Int' } }, 116 | resolve: (_, args) => { id: 1 } 117 | }); 118 | GQL.addQuery('Simple', q); 119 | expect(GQL.addQuery.bind(GQL, 'Simple', q)).to.throw(Error, /GraysQL Error/); 120 | }); 121 | it('should allow to overwrite queries when specified', function () { 122 | const q = (GQL) => ({ 123 | type: 'Simple', 124 | args: { id: { type: 'Int' } }, 125 | resolve: (_, args) => { id: 1 } 126 | }); 127 | GQL.addQuery('Simple', q); 128 | expect(GQL.addQuery.bind(GQL, 'Simple', q, true)).to.not.throw(Error, /GraysQL Error/); 129 | }); 130 | it('should return the added query', function () { 131 | const q = (GQL) => ({ 132 | type: 'Simple', 133 | args: { id: { type: 'Int' } }, 134 | resolve: (_, args) => { id: 1 } 135 | }); 136 | expect(JSON.stringify(GQL.addQuery('Simple', q))).to.equal(JSON.stringify(q(GQL))); 137 | }); 138 | }); 139 | 140 | describe('#addMutation(name, mutation, [ovewrite])', function () { 141 | let GQL; 142 | beforeEach(function () { 143 | GQL = new GraysQL(); 144 | }); 145 | it('should only add functions', function () { 146 | expect(GQL.addMutation.bind(GQL, 'asdfadf', 'asfa')).to.throw(TypeError, /GraysQL Error: Expected mutation to be a function/); 147 | expect(GQL.addMutation.bind(GQL, 'asdfadf', x => x)).to.not.throw(TypeError, /GraysQL Error: Expected mutation to be a function/); 148 | }); 149 | it('should not add a mutation with an undefined name', function () { 150 | const user = TestUser().mutations.createUser; 151 | expect(GQL.addMutation.bind(GQL, null, user)).to.throw(Error, /GraysQL Error: Missing mutation name/); 152 | expect(GQL.addMutation.bind(GQL, undefined, user)).to.throw(Error, /GraysQL Error: Missing mutation name/); 153 | expect(GQL.addMutation.bind(GQL, '', user)).to.throw(Error, /GraysQL Error: Missing mutation name/); 154 | }); 155 | it('should not overwrite a mutation by default', function () { 156 | GQL.registerType(TestUser); 157 | const user = TestUser().mutations.createUser; 158 | expect(GQL.addMutation.bind(GQL, 'createUser', user)).to.throw(Error, /GraysQL Error: Mutation/); 159 | }); 160 | it('should allow to overwrite mutations when specified', function () { 161 | GQL.registerType(TestUser); 162 | const user = TestUser().mutations.createUser; 163 | expect(GQL.addMutation.bind(GQL, 'createUser', user, true)).to.not.throw(Error, /GraysQL Error: Mutation/); 164 | }); 165 | it('should return the added mutation', function () { 166 | const user = TestUser().mutations.createUser; 167 | expect(JSON.stringify(GQL.addMutation('createUser', user))).to.equal(JSON.stringify(user(GQL))); 168 | }); 169 | }); 170 | 171 | describe('#generateSchema()', function () { 172 | let GQL; 173 | before(function () { 174 | GQL = new GraysQL({ DB }); 175 | GQL.registerType(TestGroup); 176 | GQL.registerType(TestUser); 177 | GQL.registerInterface(TestEmployee); 178 | }); 179 | it('should generate a valid schema', function (done) { 180 | expect(GQL.generateSchema.bind(GQL)).to.not.throw(Error); 181 | const Schema = GQL.generateSchema(); 182 | const query = `query GetUser { 183 | user(id: 1) { 184 | id, 185 | nick, 186 | group { 187 | id, 188 | name, 189 | members { 190 | id 191 | } 192 | } 193 | } 194 | }`; 195 | const expected = { 196 | data: { 197 | user: { 198 | id: 1, 199 | nick: 'Lars', 200 | group: { 201 | id: 1, 202 | name: 'Group 1', 203 | members: [{ id: 1 }, { id: 2 }] 204 | } 205 | } 206 | } 207 | }; 208 | graphql.graphql(Schema, query) 209 | .then(result => { 210 | expect(result).to.deep.equal(expected); 211 | done(); 212 | }) 213 | .catch(err => done(err)); 214 | }); 215 | it('should generate a schema with all the specified objects', function () { 216 | const strGenSchema = GraphQLUtils.printSchema(GQL.generateSchema()); 217 | const strManSchema = GraphQLUtils.printSchema(TestSchema.Schema); 218 | expect(strGenSchema).to.equal(strManSchema); 219 | }); 220 | }); 221 | }); 222 | 223 | }; 224 | -------------------------------------------------------------------------------- /test/unit/graysql/interface.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | const expect = require('chai').expect; 5 | 6 | const DB = require('../../support/db'); 7 | const TestEmployee = require('../../support/test-schema-dir/interfaces/employee'); 8 | 9 | 10 | module.exports = function (Interface) { 11 | 12 | describe('@Interface', function () { 13 | describe('#constructor', function () { 14 | it('should only accept a POJO as parameter', function () { 15 | expect(() => new Interface('asfa')).to.throw(TypeError, /GraysQL Error: Expected rawInterface to be an object/); 16 | expect(() => new Interface(x => x)).to.throw(TypeError, /GraysQL Error: Expected rawInterface to be an object/); 17 | expect(() => new Interface({})).to.not.throw(TypeError, /GraysQL Error: Expected rawInterface to be an object/); 18 | }); 19 | }); 20 | describe('#generate(types)', function () { 21 | let Employee; 22 | let testEmployee 23 | 24 | let increaseOnParseInterfaceField = 1; 25 | function onParseInterfaceField(payload) { 26 | increaseOnParseInterfaceField += 1; 27 | } 28 | 29 | let increaseOnGenerateInterface = 1; 30 | function onGenerateInterface(payload) { 31 | increaseOnGenerateInterface += 1; 32 | } 33 | 34 | before(function () { 35 | Employee = new graphql.GraphQLInterfaceType({ 36 | name: 'Interface', 37 | fields: () => ({ 38 | employeeId: { type: graphql.GraphQLString } 39 | }) 40 | }); 41 | 42 | testEmployee = new Interface(TestEmployee(), { onParseInterfaceField: [onParseInterfaceField], onGenerateInterface: [onGenerateInterface] }).generate(); 43 | }); 44 | 45 | it('should call onParseInterfaceField listeners', function () { 46 | testEmployee._typeConfig.fields(); 47 | expect(increaseOnParseInterfaceField).to.be.above(1); 48 | }); 49 | it('should call onGenerateInterface listeners', function () { 50 | expect(increaseOnGenerateInterface).to.be.above(1); 51 | }); 52 | it('should generate a valid GraphQLInterfaceType', function () { 53 | testEmployee = new Interface(TestEmployee()).generate(); 54 | expect(testEmployee).to.include.keys(Object.keys(Employee)); 55 | expect(testEmployee._typeConfig.fields()).to.include.keys(Object.keys(Employee._typeConfig.fields())); 56 | }); 57 | }); 58 | }); 59 | 60 | }; 61 | -------------------------------------------------------------------------------- /test/unit/graysql/mutation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | const expect = require('chai').expect; 5 | 6 | const SimpleType = require('../../support/types/simple'); 7 | 8 | 9 | module.exports = function (Mutation) { 10 | 11 | describe('@Mutation', function () { 12 | describe('#constructor', function () { 13 | it('should only accept a POJO as parameter', function () { 14 | expect(() => new Mutation('asdfad')).to.throw(TypeError, /GraysQL Error: Expected rawMutation to be an object/); 15 | expect(() => new Mutation(x => x)).to.throw(TypeError, /GraysQL Error: Expected rawMutation to be an object/); 16 | expect(() => new Mutation({})).to.not.throw(TypeError, /GraysQL Error: Expected rawMutation to be an object/); 17 | }); 18 | }); 19 | describe('#generate(types)', function () { 20 | let simpleMutation; 21 | let mutation; 22 | let Simple; 23 | 24 | let incrementOnParseMutationArg = 1; 25 | function onParseMutationArg(payload) { 26 | incrementOnParseMutationArg += 1; 27 | } 28 | 29 | let incrementOnGenerateMutation = 1; 30 | function onGenerateMutation(payload) { 31 | incrementOnGenerateMutation += 1; 32 | } 33 | 34 | before(function () { 35 | simpleMutation = SimpleType().mutations.createSimple; 36 | Simple = new graphql.GraphQLObjectType({ 37 | name: 'Simple', 38 | fields: () =>({ 39 | id: { type: graphql.GraphQLInt } 40 | }) 41 | }); 42 | }); 43 | 44 | beforeEach(function () { 45 | mutation = new Mutation(simpleMutation, { 46 | onParseMutationArg: [onParseMutationArg], 47 | onGenerateMutation: [onGenerateMutation] 48 | }); 49 | }); 50 | 51 | it('should call onParseMutationArg listeners', function () { 52 | mutation.generate({ Simple }); 53 | expect(incrementOnParseMutationArg).to.be.above(1); 54 | }); 55 | it('should call onGenerateMutation listeners', function () { 56 | expect(incrementOnGenerateMutation).to.be.above(1); 57 | }); 58 | it('should replace all the types in the mutation with valid GraphQL types', function () { 59 | expect(mutation.generate({ Simple }).type).to.equal(Simple); 60 | }); 61 | it('should generate non nullable arguments', function () { 62 | const expectedMutation = { 63 | type: Simple, 64 | args: { 65 | id: { type: new graphql.GraphQLNonNull(graphql.GraphQLInt) } 66 | }, 67 | resolve: (_, args) => { id: 1 } 68 | }; 69 | const testMutation = new Mutation({ 70 | type: 'Simple', 71 | args: { 72 | id: { type: 'Int!' } 73 | }, 74 | resolve: (_, args) => { id: 1 } 75 | }).generate({ Simple }); 76 | expect(JSON.stringify(testMutation)).to.equal(JSON.stringify(expectedMutation)); 77 | }); 78 | it('should generate a valid mutation', function () { 79 | const manMutation = { 80 | type: Simple, 81 | args: { 82 | id: { type: graphql.GraphQLInt } 83 | }, 84 | resolve: (_, args) => { id: 1 } 85 | }; 86 | expect(JSON.stringify(mutation.generate({ Simple }))).to.equal(JSON.stringify(manMutation)); 87 | }); 88 | }); 89 | }); 90 | 91 | }; 92 | -------------------------------------------------------------------------------- /test/unit/graysql/query.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | const expect = require('chai').expect; 5 | 6 | const SimpleType = require('../../support/types/simple'); 7 | 8 | 9 | module.exports = function (Query) { 10 | 11 | describe('@Query', function () { 12 | 13 | describe('#constructor(rawQuery)', function () { 14 | it('should only accept a POJO as parameter', function () { 15 | expect(() => new Query('asdfad')).to.throw(TypeError, /GraysQL Error/); 16 | expect(() => new Query(x => x)).to.throw(TypeError, /GraysQL Error/); 17 | expect(() => new Query({})).to.not.throw(TypeError, /GraysQL Error/); 18 | }); 19 | }); 20 | 21 | describe('#generate(types)', function () { 22 | let Simple; 23 | let query; 24 | 25 | let increaseOnParseQueryArg = 1; 26 | function onParseQueryArg(payload) { 27 | increaseOnParseQueryArg += 1; 28 | } 29 | 30 | let increaseOnGenerateQuery = 1; 31 | function onGenerateQuery(payload) { 32 | increaseOnGenerateQuery += 1; 33 | } 34 | 35 | before(function () { 36 | Simple = new graphql.GraphQLObjectType({ 37 | name: 'Simple', 38 | fields: () => ({ 39 | id: { type: graphql.GraphQLInt } 40 | }) 41 | }); 42 | 43 | query = new Query(SimpleType().queries.simple, { 44 | onParseQueryArg: [onParseQueryArg], 45 | onGenerateQuery: [onGenerateQuery] 46 | }); 47 | }); 48 | 49 | it('should call onParseQueryArg listeners', function () { 50 | query.generate({ Simple }); 51 | expect(increaseOnParseQueryArg).to.be.above(1); 52 | }); 53 | it('should call onGenerateQuery listeners', function () { 54 | expect(increaseOnGenerateQuery).to.be.above(1); 55 | }); 56 | 57 | it('should replace all the types in the query with valid GraphQL types', function () { 58 | expect(query.generate({ Simple }).type).to.equal(Simple); 59 | }); 60 | 61 | it('should generate non nullable arguments', function () { 62 | const expectedQuery = { 63 | type: Simple, 64 | args: { 65 | id: { type: new graphql.GraphQLNonNull(graphql.GraphQLInt) } 66 | }, 67 | resolve: (_, args) => { id: 1 } 68 | }; 69 | const testQuery = new Query({ 70 | type: 'Simple', 71 | args: { 72 | id: { type: 'Int!' } 73 | }, 74 | resolve: (_, args) => { id: 1 } 75 | }).generate({ Simple }); 76 | expect(JSON.stringify(testQuery)).to.equal(JSON.stringify(expectedQuery)); 77 | }); 78 | 79 | it('should generate a valid query', function () { 80 | const manQuery = { 81 | type: Simple, 82 | args: { 83 | id: { type: graphql.GraphQLInt } 84 | }, 85 | resolve: (_, args) => { id: 1 } 86 | }; 87 | expect(JSON.stringify(query.generate({ Simple }))).to.equal(JSON.stringify(manQuery)); 88 | }); 89 | 90 | }); 91 | }); 92 | 93 | }; 94 | -------------------------------------------------------------------------------- /test/unit/graysql/type.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const graphql = require('graphql'); 4 | const expect = require('chai').expect; 5 | 6 | const DB = require('../../support/db'); 7 | const SimpleType = require('../../support/types/simple'); 8 | const TestUser = require('../../support/types/user'); 9 | const TestGroup = require('../../support/types/group'); 10 | 11 | 12 | module.exports = function (Type) { 13 | 14 | describe('@Type', function () { 15 | describe('#constructor(rawType)', function () { 16 | it('should only accept a POJO as parameter', function () { 17 | expect(() => new Type('adsfa')).to.throw(TypeError, /GraysQL Error: Expected rawType to be an object/); 18 | expect(() => new Type(x => x)).to.throw(TypeError, /GraysQL Error: Expected rawType to be an object/); 19 | expect(() => new Type({})).to.not.throw(TypeError, /GraysQL Error: Expected rawType to be an object/); 20 | }); 21 | }); 22 | describe('#generate(types, interfaces)', function () { 23 | let User; 24 | let Group; 25 | let types; 26 | let finalTypes; 27 | 28 | let increaseOnParseTypeField = 1; 29 | function onParseTypeField(payload) { 30 | increaseOnParseTypeField += 1; 31 | } 32 | 33 | let increaseOnGenerateType = 1; 34 | function onGenerateType(payload) { 35 | increaseOnGenerateType += 1; 36 | } 37 | 38 | before(function () { 39 | User = new graphql.GraphQLObjectType({ 40 | name: 'User', 41 | fields: () => ({ 42 | id: { type: graphql.GraphQLInt }, 43 | nick: { type: graphql.GraphQLString }, 44 | group: { type: Group } 45 | }) 46 | }); 47 | Group = new graphql.GraphQLObjectType({ 48 | name: 'Group', 49 | fields: () => ({ 50 | id: { type: graphql.GraphQLInt }, 51 | name: { type: graphql.GraphQLString }, 52 | members: { type: new graphql.GraphQLList(User) } 53 | }) 54 | }); 55 | 56 | types = { 57 | User: new Type(TestUser({ options: { DB }}), { onParseTypeField: [onParseTypeField], onGenerateType: [onGenerateType] }), 58 | Group: new Type(TestGroup({ options: { DB }})), 59 | }; 60 | 61 | finalTypes = { User: {}, Group: {} }; 62 | finalTypes['User'] = types['User'].generate(finalTypes); 63 | finalTypes['Group'] = types['Group'].generate(finalTypes); 64 | }); 65 | 66 | it('should call onParseTypeField listeners', function () { 67 | types['User'].generate(finalTypes)._typeConfig.fields(); 68 | expect(increaseOnParseTypeField).to.be.above(1); 69 | }); 70 | it('should call onGenerateType listeners', function () { 71 | expect(increaseOnGenerateType).to.be.above(1); 72 | }); 73 | it('should generate a valid GraphQLObjectType', function () { 74 | expect(finalTypes['User']).to.include.keys(Object.keys(User)); 75 | expect(finalTypes['User']._typeConfig.fields()).to.include.keys(Object.keys(User._typeConfig.fields())); 76 | }); 77 | it('should parse args in fields', function () { 78 | expect(finalTypes['User']._typeConfig.fields().dummy).to.include.keys(['args']); 79 | expect(finalTypes['User']._typeConfig.fields().dummy.args).to.include.keys(['id']); 80 | expect(finalTypes['User']._typeConfig.fields().dummy.args.id.type.name).to.equal('String'); 81 | }); 82 | it('should link to other GraphQLObjectTypes if specified', function () { 83 | expect(finalTypes['User']._typeConfig.fields().group.type).to.equal(finalTypes['Group']); 84 | expect(JSON.stringify(finalTypes['Group']._typeConfig.fields().members.type)).to.equal(JSON.stringify(new graphql.GraphQLList(finalTypes['User']))); 85 | }); 86 | }); 87 | }); 88 | 89 | }; 90 | -------------------------------------------------------------------------------- /test/unit/utils/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const expect = require('chai').expect; 4 | 5 | 6 | module.exports = function (Utils) { 7 | 8 | describe('@Utils', function () { 9 | describe('#bindAll(listeners, thisArg)', function () { 10 | }); 11 | }); 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/unit/utils/type-parser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const expect = require('chai').expect; 4 | const graphql = require('graphql'); 5 | 6 | 7 | module.exports = function (TypeParser) { 8 | 9 | describe('@TypeParser', function () { 10 | let SimpleType; 11 | before(function () { 12 | SimpleType = new graphql.GraphQLObjectType({ 13 | name: 'Simple', 14 | fields: () => ({ 15 | id: { type: graphql.GraphQLInt } 16 | }) 17 | }); 18 | }); 19 | describe('#parseType(type, dependencies)', function () { 20 | it('should parse simple types: `Int`, `String`, dependencies, etc', function () { 21 | expect(TypeParser.parseType('Int')).to.deep.equal(graphql.GraphQLInt); 22 | expect(TypeParser.parseType('String')).to.deep.equal(graphql.GraphQLString); 23 | expect(TypeParser.parseType('Simple', { 'Simple': SimpleType })).to.deep.equal(SimpleType); 24 | }); 25 | it('should parse array versions of the simple types', function () { 26 | expect(TypeParser.parseType('[Int]')).to.deep.equal(new graphql.GraphQLList(graphql.GraphQLInt)); 27 | expect(TypeParser.parseType('[String]')).to.deep.equal(new graphql.GraphQLList(graphql.GraphQLString)); 28 | expect(TypeParser.parseType('[Simple]', { 'Simple': SimpleType })).to.deep.equal(new graphql.GraphQLList(SimpleType)); 29 | }); 30 | it('should parse non nullable versions of all types', function () { 31 | expect(TypeParser.parseType('Int!')).to.deep.equal(new graphql.GraphQLNonNull(graphql.GraphQLInt)); 32 | expect(TypeParser.parseType('[Int]!')).to.deep.equal(new graphql.GraphQLNonNull(new graphql.GraphQLList(graphql.GraphQLInt))); 33 | expect(TypeParser.parseType('String!')).to.deep.equal(new graphql.GraphQLNonNull(graphql.GraphQLString)); 34 | expect(TypeParser.parseType('[String]!')).to.deep.equal(new graphql.GraphQLNonNull(new graphql.GraphQLList(graphql.GraphQLString))); 35 | expect(TypeParser.parseType('Simple!', { 'Simple': SimpleType })).to.deep.equal(new graphql.GraphQLNonNull(SimpleType)); 36 | expect(TypeParser.parseType('[Simple]!', { 'Simple': SimpleType })).to.deep.equal(new graphql.GraphQLNonNull(new graphql.GraphQLList(SimpleType))); 37 | }); 38 | }); 39 | }); 40 | 41 | }; 42 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | abbrev@1, abbrev@1.0.x: 6 | version "1.0.9" 7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" 8 | 9 | align-text@^0.1.1, align-text@^0.1.3: 10 | version "0.1.4" 11 | resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" 12 | dependencies: 13 | kind-of "^3.0.2" 14 | longest "^1.0.1" 15 | repeat-string "^1.5.2" 16 | 17 | amdefine@>=0.0.4: 18 | version "1.0.1" 19 | resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" 20 | 21 | ansi-escapes@^1.1.0: 22 | version "1.4.0" 23 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" 24 | 25 | ansi-regex@^2.0.0: 26 | version "2.0.0" 27 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" 28 | 29 | ansi-styles@^2.2.1: 30 | version "2.2.1" 31 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 32 | 33 | argparse@^1.0.2: 34 | version "1.0.9" 35 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" 36 | dependencies: 37 | sprintf-js "~1.0.2" 38 | 39 | array-union@^1.0.1: 40 | version "1.0.2" 41 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 42 | dependencies: 43 | array-uniq "^1.0.1" 44 | 45 | array-uniq@^1.0.1: 46 | version "1.0.3" 47 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 48 | 49 | arrify@^1.0.0: 50 | version "1.0.1" 51 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 52 | 53 | assertion-error@^1.0.1: 54 | version "1.0.2" 55 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" 56 | 57 | async@1.x, async@^1.4.0: 58 | version "1.5.2" 59 | resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" 60 | 61 | async@~0.2.6: 62 | version "0.2.10" 63 | resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" 64 | 65 | balanced-match@^0.4.1: 66 | version "0.4.2" 67 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 68 | 69 | brace-expansion@^1.0.0: 70 | version "1.1.6" 71 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" 72 | dependencies: 73 | balanced-match "^0.4.1" 74 | concat-map "0.0.1" 75 | 76 | camelcase@^1.0.2: 77 | version "1.2.1" 78 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" 79 | 80 | center-align@^0.1.1: 81 | version "0.1.3" 82 | resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" 83 | dependencies: 84 | align-text "^0.1.3" 85 | lazy-cache "^1.0.3" 86 | 87 | chai@^3.4.1: 88 | version "3.5.0" 89 | resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" 90 | dependencies: 91 | assertion-error "^1.0.1" 92 | deep-eql "^0.1.3" 93 | type-detect "^1.0.0" 94 | 95 | chalk@^1.0.0: 96 | version "1.1.3" 97 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 98 | dependencies: 99 | ansi-styles "^2.2.1" 100 | escape-string-regexp "^1.0.2" 101 | has-ansi "^2.0.0" 102 | strip-ansi "^3.0.0" 103 | supports-color "^2.0.0" 104 | 105 | circular-json@^0.3.0: 106 | version "0.3.1" 107 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" 108 | 109 | cli-cursor@^1.0.1: 110 | version "1.0.2" 111 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" 112 | dependencies: 113 | restore-cursor "^1.0.1" 114 | 115 | cli-width@^1.0.1: 116 | version "1.1.1" 117 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-1.1.1.tgz#a4d293ef67ebb7b88d4a4d42c0ccf00c4d1e366d" 118 | 119 | cliui@^2.1.0: 120 | version "2.1.0" 121 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" 122 | dependencies: 123 | center-align "^0.1.1" 124 | right-align "^0.1.1" 125 | wordwrap "0.0.2" 126 | 127 | code-point-at@^1.0.0: 128 | version "1.1.0" 129 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 130 | 131 | commander@0.6.1: 132 | version "0.6.1" 133 | resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" 134 | 135 | commander@2.3.0: 136 | version "2.3.0" 137 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" 138 | 139 | concat-map@0.0.1: 140 | version "0.0.1" 141 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 142 | 143 | concat-stream@^1.4.6: 144 | version "1.5.2" 145 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" 146 | dependencies: 147 | inherits "~2.0.1" 148 | readable-stream "~2.0.0" 149 | typedarray "~0.0.5" 150 | 151 | core-util-is@~1.0.0: 152 | version "1.0.2" 153 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 154 | 155 | d@^0.1.1, d@~0.1.1: 156 | version "0.1.1" 157 | resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" 158 | dependencies: 159 | es5-ext "~0.10.2" 160 | 161 | debug@2.2.0, debug@^2.1.1: 162 | version "2.2.0" 163 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" 164 | dependencies: 165 | ms "0.7.1" 166 | 167 | decamelize@^1.0.0: 168 | version "1.2.0" 169 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 170 | 171 | deep-eql@^0.1.3: 172 | version "0.1.3" 173 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" 174 | dependencies: 175 | type-detect "0.1.1" 176 | 177 | deep-is@~0.1.3: 178 | version "0.1.3" 179 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 180 | 181 | del@^2.0.2: 182 | version "2.2.2" 183 | resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" 184 | dependencies: 185 | globby "^5.0.0" 186 | is-path-cwd "^1.0.0" 187 | is-path-in-cwd "^1.0.0" 188 | object-assign "^4.0.1" 189 | pify "^2.0.0" 190 | pinkie-promise "^2.0.0" 191 | rimraf "^2.2.8" 192 | 193 | diff@1.4.0: 194 | version "1.4.0" 195 | resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" 196 | 197 | doctrine@^0.7.1: 198 | version "0.7.2" 199 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" 200 | dependencies: 201 | esutils "^1.1.6" 202 | isarray "0.0.1" 203 | 204 | es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: 205 | version "0.10.12" 206 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" 207 | dependencies: 208 | es6-iterator "2" 209 | es6-symbol "~3.1" 210 | 211 | es6-iterator@2: 212 | version "2.0.0" 213 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" 214 | dependencies: 215 | d "^0.1.1" 216 | es5-ext "^0.10.7" 217 | es6-symbol "3" 218 | 219 | es6-map@^0.1.3: 220 | version "0.1.4" 221 | resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" 222 | dependencies: 223 | d "~0.1.1" 224 | es5-ext "~0.10.11" 225 | es6-iterator "2" 226 | es6-set "~0.1.3" 227 | es6-symbol "~3.1.0" 228 | event-emitter "~0.3.4" 229 | 230 | es6-set@~0.1.3: 231 | version "0.1.4" 232 | resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" 233 | dependencies: 234 | d "~0.1.1" 235 | es5-ext "~0.10.11" 236 | es6-iterator "2" 237 | es6-symbol "3" 238 | event-emitter "~0.3.4" 239 | 240 | es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: 241 | version "3.1.0" 242 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" 243 | dependencies: 244 | d "~0.1.1" 245 | es5-ext "~0.10.11" 246 | 247 | es6-weak-map@^2.0.1: 248 | version "2.0.1" 249 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" 250 | dependencies: 251 | d "^0.1.1" 252 | es5-ext "^0.10.8" 253 | es6-iterator "2" 254 | es6-symbol "3" 255 | 256 | escape-string-regexp@1.0.2, escape-string-regexp@^1.0.2: 257 | version "1.0.2" 258 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" 259 | 260 | escape-string-regexp@^1.0.5: 261 | version "1.0.5" 262 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 263 | 264 | escodegen@1.8.x: 265 | version "1.8.1" 266 | resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" 267 | dependencies: 268 | esprima "^2.7.1" 269 | estraverse "^1.9.1" 270 | esutils "^2.0.2" 271 | optionator "^0.8.1" 272 | optionalDependencies: 273 | source-map "~0.2.0" 274 | 275 | escope@^3.3.0: 276 | version "3.6.0" 277 | resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" 278 | dependencies: 279 | es6-map "^0.1.3" 280 | es6-weak-map "^2.0.1" 281 | esrecurse "^4.1.0" 282 | estraverse "^4.1.1" 283 | 284 | eslint@^1.10.3: 285 | version "1.10.3" 286 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-1.10.3.tgz#fb19a91b13c158082bbca294b17d979bc8353a0a" 287 | dependencies: 288 | chalk "^1.0.0" 289 | concat-stream "^1.4.6" 290 | debug "^2.1.1" 291 | doctrine "^0.7.1" 292 | escape-string-regexp "^1.0.2" 293 | escope "^3.3.0" 294 | espree "^2.2.4" 295 | estraverse "^4.1.1" 296 | estraverse-fb "^1.3.1" 297 | esutils "^2.0.2" 298 | file-entry-cache "^1.1.1" 299 | glob "^5.0.14" 300 | globals "^8.11.0" 301 | handlebars "^4.0.0" 302 | inquirer "^0.11.0" 303 | is-my-json-valid "^2.10.0" 304 | is-resolvable "^1.0.0" 305 | js-yaml "3.4.5" 306 | json-stable-stringify "^1.0.0" 307 | lodash.clonedeep "^3.0.1" 308 | lodash.merge "^3.3.2" 309 | lodash.omit "^3.1.0" 310 | minimatch "^3.0.0" 311 | mkdirp "^0.5.0" 312 | object-assign "^4.0.1" 313 | optionator "^0.6.0" 314 | path-is-absolute "^1.0.0" 315 | path-is-inside "^1.0.1" 316 | shelljs "^0.5.3" 317 | strip-json-comments "~1.0.1" 318 | text-table "~0.2.0" 319 | user-home "^2.0.0" 320 | xml-escape "~1.0.0" 321 | 322 | espree@^2.2.4: 323 | version "2.2.5" 324 | resolved "https://registry.yarnpkg.com/espree/-/espree-2.2.5.tgz#df691b9310889402aeb29cc066708c56690b854b" 325 | 326 | esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: 327 | version "2.7.3" 328 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 329 | 330 | esrecurse@^4.1.0: 331 | version "4.1.0" 332 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" 333 | dependencies: 334 | estraverse "~4.1.0" 335 | object-assign "^4.0.1" 336 | 337 | estraverse-fb@^1.3.1: 338 | version "1.3.1" 339 | resolved "https://registry.yarnpkg.com/estraverse-fb/-/estraverse-fb-1.3.1.tgz#160e75a80e605b08ce894bcce2fe3e429abf92bf" 340 | 341 | estraverse@^1.9.1: 342 | version "1.9.3" 343 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" 344 | 345 | estraverse@^4.1.1: 346 | version "4.2.0" 347 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 348 | 349 | estraverse@~4.1.0: 350 | version "4.1.1" 351 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" 352 | 353 | esutils@^1.1.6: 354 | version "1.1.6" 355 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375" 356 | 357 | esutils@^2.0.2: 358 | version "2.0.2" 359 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 360 | 361 | event-emitter@~0.3.4: 362 | version "0.3.4" 363 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" 364 | dependencies: 365 | d "~0.1.1" 366 | es5-ext "~0.10.7" 367 | 368 | exit-hook@^1.0.0: 369 | version "1.1.1" 370 | resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" 371 | 372 | fast-levenshtein@~1.0.6: 373 | version "1.0.7" 374 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz#0178dcdee023b92905193af0959e8a7639cfdcb9" 375 | 376 | fast-levenshtein@~2.0.4: 377 | version "2.0.5" 378 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" 379 | 380 | figures@^1.3.5: 381 | version "1.7.0" 382 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" 383 | dependencies: 384 | escape-string-regexp "^1.0.5" 385 | object-assign "^4.1.0" 386 | 387 | file-entry-cache@^1.1.1: 388 | version "1.3.1" 389 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" 390 | dependencies: 391 | flat-cache "^1.2.1" 392 | object-assign "^4.0.1" 393 | 394 | flat-cache@^1.2.1: 395 | version "1.2.1" 396 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" 397 | dependencies: 398 | circular-json "^0.3.0" 399 | del "^2.0.2" 400 | graceful-fs "^4.1.2" 401 | write "^0.2.1" 402 | 403 | fs.realpath@^1.0.0: 404 | version "1.0.0" 405 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 406 | 407 | generate-function@^2.0.0: 408 | version "2.0.0" 409 | resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" 410 | 411 | generate-object-property@^1.1.0: 412 | version "1.2.0" 413 | resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" 414 | dependencies: 415 | is-property "^1.0.0" 416 | 417 | glob@3.2.11: 418 | version "3.2.11" 419 | resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" 420 | dependencies: 421 | inherits "2" 422 | minimatch "0.3" 423 | 424 | glob@^5.0.14, glob@^5.0.15: 425 | version "5.0.15" 426 | resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" 427 | dependencies: 428 | inflight "^1.0.4" 429 | inherits "2" 430 | minimatch "2 || 3" 431 | once "^1.3.0" 432 | path-is-absolute "^1.0.0" 433 | 434 | glob@^7.0.3, glob@^7.0.5: 435 | version "7.1.1" 436 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 437 | dependencies: 438 | fs.realpath "^1.0.0" 439 | inflight "^1.0.4" 440 | inherits "2" 441 | minimatch "^3.0.2" 442 | once "^1.3.0" 443 | path-is-absolute "^1.0.0" 444 | 445 | globals@^8.11.0: 446 | version "8.18.0" 447 | resolved "https://registry.yarnpkg.com/globals/-/globals-8.18.0.tgz#93d4a62bdcac38cfafafc47d6b034768cb0ffcb4" 448 | 449 | globby@^5.0.0: 450 | version "5.0.0" 451 | resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" 452 | dependencies: 453 | array-union "^1.0.1" 454 | arrify "^1.0.0" 455 | glob "^7.0.3" 456 | object-assign "^4.0.1" 457 | pify "^2.0.0" 458 | pinkie-promise "^2.0.0" 459 | 460 | graceful-fs@^4.1.2: 461 | version "4.1.11" 462 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 463 | 464 | graphql-relay@^0.4.3: 465 | version "0.4.4" 466 | resolved "https://registry.yarnpkg.com/graphql-relay/-/graphql-relay-0.4.4.tgz#876a654445b6af4539f81cb9befd5cd7ead129dd" 467 | 468 | graphql@^0.8.2: 469 | version "0.8.2" 470 | resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.8.2.tgz#eb1bb524b38104bbf2c9157f9abc67db2feba7d2" 471 | dependencies: 472 | iterall "1.0.2" 473 | 474 | growl@1.9.2: 475 | version "1.9.2" 476 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" 477 | 478 | handlebars@^4.0.0, handlebars@^4.0.1: 479 | version "4.0.6" 480 | resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" 481 | dependencies: 482 | async "^1.4.0" 483 | optimist "^0.6.1" 484 | source-map "^0.4.4" 485 | optionalDependencies: 486 | uglify-js "^2.6" 487 | 488 | has-ansi@^2.0.0: 489 | version "2.0.0" 490 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 491 | dependencies: 492 | ansi-regex "^2.0.0" 493 | 494 | has-flag@^1.0.0: 495 | version "1.0.0" 496 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 497 | 498 | inflight@^1.0.4: 499 | version "1.0.6" 500 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 501 | dependencies: 502 | once "^1.3.0" 503 | wrappy "1" 504 | 505 | inherits@2, inherits@~2.0.1: 506 | version "2.0.3" 507 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 508 | 509 | inquirer@^0.11.0: 510 | version "0.11.4" 511 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.11.4.tgz#81e3374e8361beaff2d97016206d359d0b32fa4d" 512 | dependencies: 513 | ansi-escapes "^1.1.0" 514 | ansi-regex "^2.0.0" 515 | chalk "^1.0.0" 516 | cli-cursor "^1.0.1" 517 | cli-width "^1.0.1" 518 | figures "^1.3.5" 519 | lodash "^3.3.1" 520 | readline2 "^1.0.1" 521 | run-async "^0.1.0" 522 | rx-lite "^3.1.2" 523 | string-width "^1.0.1" 524 | strip-ansi "^3.0.0" 525 | through "^2.3.6" 526 | 527 | is-buffer@^1.0.2: 528 | version "1.1.4" 529 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" 530 | 531 | is-fullwidth-code-point@^1.0.0: 532 | version "1.0.0" 533 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 534 | dependencies: 535 | number-is-nan "^1.0.0" 536 | 537 | is-my-json-valid@^2.10.0: 538 | version "2.15.0" 539 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" 540 | dependencies: 541 | generate-function "^2.0.0" 542 | generate-object-property "^1.1.0" 543 | jsonpointer "^4.0.0" 544 | xtend "^4.0.0" 545 | 546 | is-path-cwd@^1.0.0: 547 | version "1.0.0" 548 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" 549 | 550 | is-path-in-cwd@^1.0.0: 551 | version "1.0.0" 552 | resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" 553 | dependencies: 554 | is-path-inside "^1.0.0" 555 | 556 | is-path-inside@^1.0.0: 557 | version "1.0.0" 558 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" 559 | dependencies: 560 | path-is-inside "^1.0.1" 561 | 562 | is-property@^1.0.0: 563 | version "1.0.2" 564 | resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" 565 | 566 | is-resolvable@^1.0.0: 567 | version "1.0.0" 568 | resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" 569 | dependencies: 570 | tryit "^1.0.1" 571 | 572 | isarray@0.0.1: 573 | version "0.0.1" 574 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 575 | 576 | isarray@~1.0.0: 577 | version "1.0.0" 578 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 579 | 580 | isexe@^1.1.1: 581 | version "1.1.2" 582 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" 583 | 584 | istanbul@^0.4.2: 585 | version "0.4.5" 586 | resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" 587 | dependencies: 588 | abbrev "1.0.x" 589 | async "1.x" 590 | escodegen "1.8.x" 591 | esprima "2.7.x" 592 | glob "^5.0.15" 593 | handlebars "^4.0.1" 594 | js-yaml "3.x" 595 | mkdirp "0.5.x" 596 | nopt "3.x" 597 | once "1.x" 598 | resolve "1.1.x" 599 | supports-color "^3.1.0" 600 | which "^1.1.1" 601 | wordwrap "^1.0.0" 602 | 603 | iterall@1.0.2: 604 | version "1.0.2" 605 | resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.0.2.tgz#41a2e96ce9eda5e61c767ee5dc312373bb046e91" 606 | 607 | jade@0.26.3: 608 | version "0.26.3" 609 | resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" 610 | dependencies: 611 | commander "0.6.1" 612 | mkdirp "0.3.0" 613 | 614 | js-yaml@3.4.5, js-yaml@3.x: 615 | version "3.4.5" 616 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.4.5.tgz#c3403797df12b91866574f2de23646fe8cafb44d" 617 | dependencies: 618 | argparse "^1.0.2" 619 | esprima "^2.6.0" 620 | 621 | json-stable-stringify@^1.0.0: 622 | version "1.0.1" 623 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 624 | dependencies: 625 | jsonify "~0.0.0" 626 | 627 | jsonify@~0.0.0: 628 | version "0.0.0" 629 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 630 | 631 | jsonpointer@^4.0.0: 632 | version "4.0.0" 633 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" 634 | 635 | kind-of@^3.0.2: 636 | version "3.1.0" 637 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" 638 | dependencies: 639 | is-buffer "^1.0.2" 640 | 641 | lazy-cache@^1.0.3: 642 | version "1.0.4" 643 | resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" 644 | 645 | levn@~0.2.5: 646 | version "0.2.5" 647 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.2.5.tgz#ba8d339d0ca4a610e3a3f145b9caf48807155054" 648 | dependencies: 649 | prelude-ls "~1.1.0" 650 | type-check "~0.3.1" 651 | 652 | levn@~0.3.0: 653 | version "0.3.0" 654 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 655 | dependencies: 656 | prelude-ls "~1.1.2" 657 | type-check "~0.3.2" 658 | 659 | lodash._arraycopy@^3.0.0: 660 | version "3.0.0" 661 | resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" 662 | 663 | lodash._arrayeach@^3.0.0: 664 | version "3.0.0" 665 | resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" 666 | 667 | lodash._arraymap@^3.0.0: 668 | version "3.0.0" 669 | resolved "https://registry.yarnpkg.com/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz#1a8fd0f4c0df4b61dea076d717cdc97f0a3c3e66" 670 | 671 | lodash._baseassign@^3.0.0: 672 | version "3.2.0" 673 | resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" 674 | dependencies: 675 | lodash._basecopy "^3.0.0" 676 | lodash.keys "^3.0.0" 677 | 678 | lodash._baseclone@^3.0.0: 679 | version "3.3.0" 680 | resolved "https://registry.yarnpkg.com/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" 681 | dependencies: 682 | lodash._arraycopy "^3.0.0" 683 | lodash._arrayeach "^3.0.0" 684 | lodash._baseassign "^3.0.0" 685 | lodash._basefor "^3.0.0" 686 | lodash.isarray "^3.0.0" 687 | lodash.keys "^3.0.0" 688 | 689 | lodash._basecopy@^3.0.0: 690 | version "3.0.1" 691 | resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" 692 | 693 | lodash._basedifference@^3.0.0: 694 | version "3.0.3" 695 | resolved "https://registry.yarnpkg.com/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz#f2c204296c2a78e02b389081b6edcac933cf629c" 696 | dependencies: 697 | lodash._baseindexof "^3.0.0" 698 | lodash._cacheindexof "^3.0.0" 699 | lodash._createcache "^3.0.0" 700 | 701 | lodash._baseflatten@^3.0.0: 702 | version "3.1.4" 703 | resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" 704 | dependencies: 705 | lodash.isarguments "^3.0.0" 706 | lodash.isarray "^3.0.0" 707 | 708 | lodash._basefor@^3.0.0: 709 | version "3.0.3" 710 | resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" 711 | 712 | lodash._baseindexof@^3.0.0: 713 | version "3.1.0" 714 | resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" 715 | 716 | lodash._bindcallback@^3.0.0: 717 | version "3.0.1" 718 | resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" 719 | 720 | lodash._cacheindexof@^3.0.0: 721 | version "3.0.2" 722 | resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" 723 | 724 | lodash._createassigner@^3.0.0: 725 | version "3.1.1" 726 | resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" 727 | dependencies: 728 | lodash._bindcallback "^3.0.0" 729 | lodash._isiterateecall "^3.0.0" 730 | lodash.restparam "^3.0.0" 731 | 732 | lodash._createcache@^3.0.0: 733 | version "3.1.2" 734 | resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" 735 | dependencies: 736 | lodash._getnative "^3.0.0" 737 | 738 | lodash._getnative@^3.0.0: 739 | version "3.9.1" 740 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 741 | 742 | lodash._isiterateecall@^3.0.0: 743 | version "3.0.9" 744 | resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" 745 | 746 | lodash._pickbyarray@^3.0.0: 747 | version "3.0.2" 748 | resolved "https://registry.yarnpkg.com/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz#1f898d9607eb560b0e167384b77c7c6d108aa4c5" 749 | 750 | lodash._pickbycallback@^3.0.0: 751 | version "3.0.0" 752 | resolved "https://registry.yarnpkg.com/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz#ff61b9a017a7b3af7d30e6c53de28afa19b8750a" 753 | dependencies: 754 | lodash._basefor "^3.0.0" 755 | lodash.keysin "^3.0.0" 756 | 757 | lodash.clonedeep@^3.0.1: 758 | version "3.0.2" 759 | resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db" 760 | dependencies: 761 | lodash._baseclone "^3.0.0" 762 | lodash._bindcallback "^3.0.0" 763 | 764 | lodash.isarguments@^3.0.0: 765 | version "3.1.0" 766 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 767 | 768 | lodash.isarray@^3.0.0: 769 | version "3.0.4" 770 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 771 | 772 | lodash.isplainobject@^3.0.0: 773 | version "3.2.0" 774 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" 775 | dependencies: 776 | lodash._basefor "^3.0.0" 777 | lodash.isarguments "^3.0.0" 778 | lodash.keysin "^3.0.0" 779 | 780 | lodash.istypedarray@^3.0.0: 781 | version "3.0.6" 782 | resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" 783 | 784 | lodash.keys@^3.0.0: 785 | version "3.1.2" 786 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 787 | dependencies: 788 | lodash._getnative "^3.0.0" 789 | lodash.isarguments "^3.0.0" 790 | lodash.isarray "^3.0.0" 791 | 792 | lodash.keysin@^3.0.0: 793 | version "3.0.8" 794 | resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" 795 | dependencies: 796 | lodash.isarguments "^3.0.0" 797 | lodash.isarray "^3.0.0" 798 | 799 | lodash.merge@^3.3.2: 800 | version "3.3.2" 801 | resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" 802 | dependencies: 803 | lodash._arraycopy "^3.0.0" 804 | lodash._arrayeach "^3.0.0" 805 | lodash._createassigner "^3.0.0" 806 | lodash._getnative "^3.0.0" 807 | lodash.isarguments "^3.0.0" 808 | lodash.isarray "^3.0.0" 809 | lodash.isplainobject "^3.0.0" 810 | lodash.istypedarray "^3.0.0" 811 | lodash.keys "^3.0.0" 812 | lodash.keysin "^3.0.0" 813 | lodash.toplainobject "^3.0.0" 814 | 815 | lodash.omit@^3.1.0: 816 | version "3.1.0" 817 | resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-3.1.0.tgz#897fe382e6413d9ac97c61f78ed1e057a00af9f3" 818 | dependencies: 819 | lodash._arraymap "^3.0.0" 820 | lodash._basedifference "^3.0.0" 821 | lodash._baseflatten "^3.0.0" 822 | lodash._bindcallback "^3.0.0" 823 | lodash._pickbyarray "^3.0.0" 824 | lodash._pickbycallback "^3.0.0" 825 | lodash.keysin "^3.0.0" 826 | lodash.restparam "^3.0.0" 827 | 828 | lodash.restparam@^3.0.0: 829 | version "3.6.1" 830 | resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" 831 | 832 | lodash.toplainobject@^3.0.0: 833 | version "3.0.0" 834 | resolved "https://registry.yarnpkg.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" 835 | dependencies: 836 | lodash._basecopy "^3.0.0" 837 | lodash.keysin "^3.0.0" 838 | 839 | lodash@^3.3.1: 840 | version "3.10.1" 841 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" 842 | 843 | longest@^1.0.1: 844 | version "1.0.1" 845 | resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" 846 | 847 | lru-cache@2: 848 | version "2.7.3" 849 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" 850 | 851 | minimatch@0.3: 852 | version "0.3.0" 853 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" 854 | dependencies: 855 | lru-cache "2" 856 | sigmund "~1.0.0" 857 | 858 | "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2: 859 | version "3.0.3" 860 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" 861 | dependencies: 862 | brace-expansion "^1.0.0" 863 | 864 | minimist@0.0.8, minimist@~0.0.1: 865 | version "0.0.8" 866 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 867 | 868 | mkdirp@0.3.0: 869 | version "0.3.0" 870 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" 871 | 872 | mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: 873 | version "0.5.1" 874 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 875 | dependencies: 876 | minimist "0.0.8" 877 | 878 | mocha@^2.3.4: 879 | version "2.5.3" 880 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" 881 | dependencies: 882 | commander "2.3.0" 883 | debug "2.2.0" 884 | diff "1.4.0" 885 | escape-string-regexp "1.0.2" 886 | glob "3.2.11" 887 | growl "1.9.2" 888 | jade "0.26.3" 889 | mkdirp "0.5.1" 890 | supports-color "1.2.0" 891 | to-iso-string "0.0.2" 892 | 893 | ms@0.7.1: 894 | version "0.7.1" 895 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" 896 | 897 | mute-stream@0.0.5: 898 | version "0.0.5" 899 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" 900 | 901 | nopt@3.x: 902 | version "3.0.6" 903 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" 904 | dependencies: 905 | abbrev "1" 906 | 907 | number-is-nan@^1.0.0: 908 | version "1.0.1" 909 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 910 | 911 | object-assign@^4.0.1, object-assign@^4.1.0: 912 | version "4.1.0" 913 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" 914 | 915 | once@1.x, once@^1.3.0: 916 | version "1.4.0" 917 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 918 | dependencies: 919 | wrappy "1" 920 | 921 | onetime@^1.0.0: 922 | version "1.1.0" 923 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" 924 | 925 | optimist@^0.6.1: 926 | version "0.6.1" 927 | resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" 928 | dependencies: 929 | minimist "~0.0.1" 930 | wordwrap "~0.0.2" 931 | 932 | optionator@^0.6.0: 933 | version "0.6.0" 934 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.6.0.tgz#b63ecbbf0e315fad4bc9827b45dc7ba45284fcb6" 935 | dependencies: 936 | deep-is "~0.1.3" 937 | fast-levenshtein "~1.0.6" 938 | levn "~0.2.5" 939 | prelude-ls "~1.1.1" 940 | type-check "~0.3.1" 941 | wordwrap "~0.0.2" 942 | 943 | optionator@^0.8.1: 944 | version "0.8.2" 945 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 946 | dependencies: 947 | deep-is "~0.1.3" 948 | fast-levenshtein "~2.0.4" 949 | levn "~0.3.0" 950 | prelude-ls "~1.1.2" 951 | type-check "~0.3.2" 952 | wordwrap "~1.0.0" 953 | 954 | os-homedir@^1.0.0: 955 | version "1.0.2" 956 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 957 | 958 | path-is-absolute@^1.0.0: 959 | version "1.0.1" 960 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 961 | 962 | path-is-inside@^1.0.1: 963 | version "1.0.2" 964 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 965 | 966 | pify@^2.0.0: 967 | version "2.3.0" 968 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 969 | 970 | pinkie-promise@^2.0.0: 971 | version "2.0.1" 972 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 973 | dependencies: 974 | pinkie "^2.0.0" 975 | 976 | pinkie@^2.0.0: 977 | version "2.0.4" 978 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 979 | 980 | prelude-ls@~1.1.0, prelude-ls@~1.1.1, prelude-ls@~1.1.2: 981 | version "1.1.2" 982 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 983 | 984 | process-nextick-args@~1.0.6: 985 | version "1.0.7" 986 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 987 | 988 | readable-stream@~2.0.0: 989 | version "2.0.6" 990 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" 991 | dependencies: 992 | core-util-is "~1.0.0" 993 | inherits "~2.0.1" 994 | isarray "~1.0.0" 995 | process-nextick-args "~1.0.6" 996 | string_decoder "~0.10.x" 997 | util-deprecate "~1.0.1" 998 | 999 | readline2@^1.0.1: 1000 | version "1.0.1" 1001 | resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" 1002 | dependencies: 1003 | code-point-at "^1.0.0" 1004 | is-fullwidth-code-point "^1.0.0" 1005 | mute-stream "0.0.5" 1006 | 1007 | repeat-string@^1.5.2: 1008 | version "1.6.1" 1009 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 1010 | 1011 | resolve@1.1.x: 1012 | version "1.1.7" 1013 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" 1014 | 1015 | restore-cursor@^1.0.1: 1016 | version "1.0.1" 1017 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" 1018 | dependencies: 1019 | exit-hook "^1.0.0" 1020 | onetime "^1.0.0" 1021 | 1022 | right-align@^0.1.1: 1023 | version "0.1.3" 1024 | resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" 1025 | dependencies: 1026 | align-text "^0.1.1" 1027 | 1028 | rimraf@^2.2.8: 1029 | version "2.5.4" 1030 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" 1031 | dependencies: 1032 | glob "^7.0.5" 1033 | 1034 | run-async@^0.1.0: 1035 | version "0.1.0" 1036 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" 1037 | dependencies: 1038 | once "^1.3.0" 1039 | 1040 | rx-lite@^3.1.2: 1041 | version "3.1.2" 1042 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" 1043 | 1044 | shelljs@^0.5.3: 1045 | version "0.5.3" 1046 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.5.3.tgz#c54982b996c76ef0c1e6b59fbdc5825f5b713113" 1047 | 1048 | sigmund@~1.0.0: 1049 | version "1.0.1" 1050 | resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" 1051 | 1052 | source-map@^0.4.4: 1053 | version "0.4.4" 1054 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" 1055 | dependencies: 1056 | amdefine ">=0.0.4" 1057 | 1058 | source-map@~0.2.0: 1059 | version "0.2.0" 1060 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" 1061 | dependencies: 1062 | amdefine ">=0.0.4" 1063 | 1064 | source-map@~0.5.1: 1065 | version "0.5.6" 1066 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" 1067 | 1068 | sprintf-js@~1.0.2: 1069 | version "1.0.3" 1070 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1071 | 1072 | string-width@^1.0.1: 1073 | version "1.0.2" 1074 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1075 | dependencies: 1076 | code-point-at "^1.0.0" 1077 | is-fullwidth-code-point "^1.0.0" 1078 | strip-ansi "^3.0.0" 1079 | 1080 | string_decoder@~0.10.x: 1081 | version "0.10.31" 1082 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 1083 | 1084 | strip-ansi@^3.0.0: 1085 | version "3.0.1" 1086 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1087 | dependencies: 1088 | ansi-regex "^2.0.0" 1089 | 1090 | strip-json-comments@~1.0.1: 1091 | version "1.0.4" 1092 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" 1093 | 1094 | supports-color@1.2.0: 1095 | version "1.2.0" 1096 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" 1097 | 1098 | supports-color@^2.0.0: 1099 | version "2.0.0" 1100 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 1101 | 1102 | supports-color@^3.1.0: 1103 | version "3.1.2" 1104 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" 1105 | dependencies: 1106 | has-flag "^1.0.0" 1107 | 1108 | text-table@~0.2.0: 1109 | version "0.2.0" 1110 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 1111 | 1112 | through@^2.3.6: 1113 | version "2.3.8" 1114 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1115 | 1116 | to-iso-string@0.0.2: 1117 | version "0.0.2" 1118 | resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" 1119 | 1120 | tryit@^1.0.1: 1121 | version "1.0.3" 1122 | resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" 1123 | 1124 | type-check@~0.3.1, type-check@~0.3.2: 1125 | version "0.3.2" 1126 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 1127 | dependencies: 1128 | prelude-ls "~1.1.2" 1129 | 1130 | type-detect@0.1.1: 1131 | version "0.1.1" 1132 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" 1133 | 1134 | type-detect@^1.0.0: 1135 | version "1.0.0" 1136 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" 1137 | 1138 | typedarray@~0.0.5: 1139 | version "0.0.6" 1140 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 1141 | 1142 | uglify-js@^2.6: 1143 | version "2.7.5" 1144 | resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" 1145 | dependencies: 1146 | async "~0.2.6" 1147 | source-map "~0.5.1" 1148 | uglify-to-browserify "~1.0.0" 1149 | yargs "~3.10.0" 1150 | 1151 | uglify-to-browserify@~1.0.0: 1152 | version "1.0.2" 1153 | resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" 1154 | 1155 | user-home@^2.0.0: 1156 | version "2.0.0" 1157 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" 1158 | dependencies: 1159 | os-homedir "^1.0.0" 1160 | 1161 | util-deprecate@~1.0.1: 1162 | version "1.0.2" 1163 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1164 | 1165 | which@^1.1.1: 1166 | version "1.2.12" 1167 | resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" 1168 | dependencies: 1169 | isexe "^1.1.1" 1170 | 1171 | window-size@0.1.0: 1172 | version "0.1.0" 1173 | resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" 1174 | 1175 | wordwrap@0.0.2: 1176 | version "0.0.2" 1177 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" 1178 | 1179 | wordwrap@^1.0.0, wordwrap@~1.0.0: 1180 | version "1.0.0" 1181 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 1182 | 1183 | wordwrap@~0.0.2: 1184 | version "0.0.3" 1185 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" 1186 | 1187 | wrappy@1: 1188 | version "1.0.2" 1189 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1190 | 1191 | write@^0.2.1: 1192 | version "0.2.1" 1193 | resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" 1194 | dependencies: 1195 | mkdirp "^0.5.1" 1196 | 1197 | xml-escape@~1.0.0: 1198 | version "1.0.0" 1199 | resolved "https://registry.yarnpkg.com/xml-escape/-/xml-escape-1.0.0.tgz#00963d697b2adf0c185c4e04e73174ba9b288eb2" 1200 | 1201 | xtend@^4.0.0: 1202 | version "4.0.1" 1203 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 1204 | 1205 | yargs@~3.10.0: 1206 | version "3.10.0" 1207 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" 1208 | dependencies: 1209 | camelcase "^1.0.2" 1210 | cliui "^2.1.0" 1211 | decamelize "^1.0.0" 1212 | window-size "0.1.0" 1213 | --------------------------------------------------------------------------------