git.iko.soy/rowtype-yoga/purescript-graphql
on master help sign in
57 files changed+4136−3821
since splitsnapshots
unifiedsplit
.gitignore+2 README.md+31−38 bower.json+23 docs/README.md+63−12 docs/_sidebar.md+7−5 docs/getting_started.md+165−32 docs/http_server.md+26−8 docs/index.html+117−90 docs/intro_to_graphql.md+43 docs/object_types.md+82 docs/scalar_types.md+92 docs/union_types.md+91 docs/v1/.nojekyll docs/v1/README.md+31 docs/v1/_sidebar.md+8 docs/context.md → docs/v1/context.md docs/v1/getting_started.md+64 docs/v1/http_server.md+62 docs/schema_and_execution.md → docs/v1/schema_and_execution.md docs/type_system.md → docs/v1/type_system.md docs/version_2.md+43 package-lock.json+736−2988 package.json+1−1 packages.dhall+2−1 spago.dhall+40−20 src/GraphQL.purs+49−9 src/GraphQL/Builtin/Introspection.purs+175 src/GraphQL/Type/Scalar.purs → src/GraphQL/Builtin/Scalar.purs+1−1 src/GraphQL/DSL.purs+864 src/GraphQL/Execution.purs+74−16 src/GraphQL/Execution/FlattenAst.purs+50 src/GraphQL/Execution/Normalize.purs+42 src/GraphQL/Execution/Result.purs+2−1 src/GraphQL/Language.purs+1−1 src/GraphQL/Language/AST.purs+2−1 src/GraphQL/Language/AST/Util.purs+10 src/GraphQL/Language/Parser.purs+40−16 src/GraphQL/Language/Printer.purs+80 src/GraphQL/OptionallyParallel.purs+30 src/GraphQL/Type.purs+17−485 src/GraphQL/Type/Class.purs+40 src/GraphQL/Type/EnumType.purs+88 src/GraphQL/Type/InputObjectType.purs+53 src/GraphQL/Type/Introspection/Datatypes.purs+174 src/GraphQL/Type/Introspection/Util.purs+76 src/GraphQL/Type/ObjectType.purs+136 src/GraphQL/Type/ScalarType.purs+57 src/GraphQL/Type/Schema.purs+8 src/GraphQL/Type/UnionType.purs+57 test/Async.purs+42 test/Execution.purs+169−54 test/Language/Parser.purs+1−1 test/Language/Parser/Field.purs+21−5 test/Language/Parser/Operation.purs+14−1 test/Language/Parser/Value.purs+7−7 test/Main.purs+4−3 test/Readme.purs+23−25
.gitignore+2
@@ -9,3 +9,5 @@
99/.purs*
1010/.psa*
1111/example/
12+/bower_components/
13+Ideas.md
README.md+31−38
@@ -1,61 +1,54 @@
11# Purescript GraphQL
22
3−PureScript GraphQL is a [GraphQL](https://graphql.org) implementation written in PureScript. It features a powerful DSL that will make building GraphQL servers as typesafe as possible.
3+[![License](https://img.shields.io/github/license/hendrikniemann/purescript-graphql.svg)](https://github.com/hendrikniemann/purescript-graphql/blob/master/LICENSE)
4+
5+PureScript GraphQL is a [GraphQL](https://graphql.org) implementation written in PureScript. It features a powerful DSL that makes building GraphQL servers as typesafe as possible.
46
57> ### 🚧 Full rewrite happening 🚧
68>
7−> This is a complete rewrite of PureScript GraphQL. If you are looking for version 1 of PureScript GraphQL make sure to check out the [1.0.1 tag](https://github.com/hendrikniemann/purescript-graphql/tree/v1.0.1).
8−>
9−> Version 2 of PureScript GraphQL will be written in PureScript and no longer depend on the JavaScript implementation under the hood. This is to support user defined execution through deriving from the classic resolver model where child resolvers are only called after the parent value has arrived.
9+> This is a complete rewrite of PureScript GraphQL. If you are looking for version 1 of PureScript GraphQL make sure to check out the [1.0.2 tag](https://github.com/hendrikniemann/purescript-graphql/tree/v1.0.2).
1010
11−[![License](https://img.shields.io/github/license/hendrikniemann/purescript-graphql.svg)](https://github.com/hendrikniemann/purescript-graphql/blob/master/LICENSE)
11+To follow the roadmap to version 2 check out the [milestone](https://github.com/hendrikniemann/purescript-graphql/milestone/1)
12+
13+## Getting started
14+
15+If you are new to PureScript GraphQL I highly recommend to follow the [tutorial](https://hendrikniemann.github.io/purescript-graphql/). ~~If you know what you are doing you can simply install `purescript-graphql` with spago.~~ (Not in the package set yet, will be done as soon as beta is out)
1216
13−## Future API
17+```
18+spago install graphql
19+```
20+
21+## Basic example
1422
15−This is a sneak peak of the future PureScript GraphQL API. If you want to give feedback please open an issue.
23+This code creates a simple schema with one query field.
24+The field takes one argument `name` and returns a string.
1625
1726```purescript
1827module Main where
1928
2029import Prelude
2130
22−import Data.Argonaut.Core (stringify)
23−import Data.Either (Either(..))
31+import Data.Argonaut (stringify)
32+import Data.Map as Map
2433import Effect (Effect)
2534import Effect.Console as Console
26−import Effect.Exception (Error)
27−import GraphQL (graphql)
28−import GraphQL.Type ((!>), (.>), (:>))
29−import GraphQL.Type as GraphQL
30−import GraphQL.Type.Scalar as Scalar
35+import GraphQL ((!>), (.>), (:>), (?>), graphql)
36+import GraphQL as GraphQL
3137
3238main :: Effect Unit
33−main = case graphql schema "{ hello }" (pure unit) of
34− Left error -> Console.error $ show error
35− Right result -> Console.log $ stringify result
36−-- {"data":{"hello":"world"}}
39+main = do
40+ result <- graphql schema """{ hello(name: "world") }""" Map.empty Nothing unit
41+ Console.log $ stringify result -- {"data":{"hello":"world"}}
3742
38−schema :: GraphQL.Schema (Either Error) Unit
39−schema = GraphQL.Schema { query: queryType }
43+schema :: GraphQL.Schema Effect Unit
44+schema = GraphQL.Schema { query: queryType, mutation: Nothing }
4045
41−queryType :: GraphQL.ObjectType (Either Error) Unit
46+queryType :: GraphQL.ObjectType Effect Unit
4247queryType =
4348 GraphQL.objectType "Query"
44− .> "The root query type."
45− :> GraphQL.field "hello" Scalar.string
46− .> "A simple field that always returns \"world\"."
47− !> (\_ _ -> pure "world")
49+ :> "The root query type."
50+ .> GraphQL.field "hello" GraphQL.string
51+ ?> GraphQL.arg @"name" GraphQL.string
52+ :> "A simple field that returns a greeting."
53+ !> (\{ name } _ -> pure $ "Hello, " <> name <> "!")
4854```
49−
50−## PureScript GraphQL v2 missing features
51−
52−This is a list of features still required to be implemented before v2 can have a first alpha release:
53−
54−- [ ] Spec compliant error handling
55− - [x] Errors contain path
56− - [ ] Errors contain location
57− - [ ] Errors propagate up to nearest nullable field
58−- [ ] Interface Types
59−- [ ] Union Types
60−- [ ] Introspection
61−- [x] \_\_typename meta field on object types
bower.jsonnew file+23
@@ -0,0 +1,23 @@
1+{
2+ "name": "purescript-graphql",
3+ "description": "PureScript GraphQL Implementation",
4+ "main": "src/Main.purs",
5+ "authors": [
6+ "hendrikniemann"
7+ ],
8+ "license": "MIT",
9+ "keywords": [
10+ "purescript",
11+ "graphql",
12+ "typesafety",
13+ "api"
14+ ],
15+ "homepage": "https://github.com/hendrikniemann/purescript-graphql",
16+ "ignore": [
17+ "**/.*",
18+ "node_modules",
19+ "bower_components",
20+ "test",
21+ "tests"
22+ ]
23+}
docs/README.md+63−12
@@ -2,30 +2,81 @@
22
33## About PureScript GraphQL
44
5−This is a tutorial on Purescript GraphQL (`purescript-graphql`), a wrapper for PureScript around the JavaScript GraphQL reference implementation [GraphQL.js](https://github.com/graphql/graphql-js) (`graphql-js`) initially developed by Facebook. The JavaScript ecosystem is definitely the most prominent one around GraphQL (even though historically neither the first client nor the first server implementation was written in JavaScript). With PureScript we can make use of the JavaScript ecosytem while at the same time enjoying typesafety and all the programming patterns we love (and hate) from pure functional programming.
5+PureScript GraphQL is a feature-lacking, production-not-ready and unblazingly slow GraphQL implementation.
6+Okay, let me rephrase that: PureScript is a highly experimental, end-to-end-typesafe and pure functional GraphQL implementation.
7+It serves mainly two purposes:
68
7−To make the use of PureScript GraphQL more idomatic it does a few type conversions. While GraphQL.js works with JavaScript's Promises, the PureScript ecosystem favours the Aff monad. Furthermore nullable values are converted to `Maybe`s. These conversions come at a price but should still be worth it compared to a full PureScript GraphQL implementation since the whole parsing and execution engine is written in JavaScript and should be very fast.
9+1. Explore the combination of functional programming concepts with GraphQL servers
10+2. Act as a motivating real life project for me to learn pure functional programming
11+
12+For you on the other hand, this implementation and the following tutorial can be fun to explore if you either come from a functional programming background and you want to learn about GraphQL or if you are familiar with GraphQL in mainstream programming languages and want to get inspired by the things that are pretty much only possible in PureScript.
13+Here are some of my proudest features:
14+
15+- Resolvers are pure functions (no surprises here)
16+- Resolver types are fully inferred
17+ - Parent type, return type and argument type are fully type inferred
18+ - Arguments translate to records just like in GraphQL.js
19+ - Use the powerful type system of PureScript - no runtime errors\*!
20+ - No codegen in the background like in GraphQL Nexus
21+- Free choice of execution context
22+ - Use `Either Error` for pure computations
23+ - Use `Effect` for effectful computations
24+ - Use `Aff` for asynchronous effectful computations
25+ - Use your own monad transformer stack for your production-grade web app
26+- Value level GraphQL schema to build your own abstractions
27+- E.g. soon available: Magically infer input and output types for your record types
28+
29+_\* Maybe not quite no runtime errors as in zero runtime errors, but - you know - less runtime errors than JS._
830
931## Prerequisites
1032
11−This tutorial assumes that you are already familiar with some PureScript and the basics of GraphQL. You can learn the basics of GraphQL on the offical [GraphQL website](http://graphql.org). If you are already very familiar with GraphQL and the JavaScript implementation this tutorial can also be a nice comparison between the languages.
33+This tutorial assumes that you are already familiar with some PureScript and the basics of GraphQL.
34+You can learn the basics of GraphQL on the offical [GraphQL website](http://graphql.org).
35+For this tutorial you will need to have some practical understanding of monads.
36+Monads are in the center of effectful code in PureScript and obviously this library.
37+You should understand how to work with effect monads like `Effect`, `Aff` or `IO` if you come from Haskell.
1238
13−For this tutorial we will be using PureScript 0.12, Pulp and Bower. You can find out how to install them on the [PureScript website](http://www.purescript.org/). All three of them need [Node.js](http://nodejs.org) and we will also make use of NPM, that comes with Node.js, to install some JavaScript dependencies.
39+For this tutorial we will be using PureScript 0.13 and Spago.
40+You can find out how to install them on the [PureScript getting started guide](https://github.com/purescript/documentation/blob/master/guides/Getting-Started.md).
41+You will also need [Node.js](http://nodejs.org) and in the later stages of this tutorial we will also make use of NPM to install some JavaScript dependencies.
42+NPM comes with Node.js and you don't have to install it.
1443
15−To try out and execute our GraphQL queries we will need a GraphQL client. Theoretically you can use CURL or Postman but I recommend the [GraphQL Playground](https://github.com/prisma/graphql-playground).
44+To try out and execute our GraphQL queries over HTTP we will need a GraphQL client.
45+In theory, you can use CURL or Postman but I recommend the [GraphQL Playground](https://github.com/prisma-labs/graphql-playground).
46+Unlike in other GraphQL ecosystems, there is no middleware package available that serves Playground or GraphiQL.
47+We will have to build our own middleware and we want to keep it simple.
1648
17−## Why GraphQL
49+## Why GraphQL?
1850
19−GraphQL is a statically typed query language and since this is a tutorial for PureScript we don't have to discuss the benefits of strong type systems. GraphQL lets us create powerful APIs that are fun to build and fun to use. GraphQL APIs are easy to extend because if we follow a few rules we can make changes without breaking our clients.
51+GraphQL is a statically typed query language and since this is a tutorial for PureScript we don't have to discuss the benefits of strong type systems.
52+GraphQL lets us create powerful APIs that are fun to build and fun to use.
53+GraphQL APIs are easy to extend because if we follow a few rules we can make changes without breaking our clients.
2054
21−## Why PureScript
55+## Why PureScript?
2256
23−PureScript is a powerful statically typed functional programming language. The static type system of PureScript pairs well with GraphQL since we can enforce that the application code actually returns the data that the API level needs at compile time. In comparison, GraphQL.js also checks the values of all leaf types at runtime but for many bugs this might already be to late. GraphQL.js also comes with Flow types. Unfortunately the Flow type system is not strong enough to express the complex raltionships between the GraphQL types. This leaves the resolvers untyped - the main source of errors since implementing resolvers is the bread and butter of GraphQL APIs. While there are [effords in the community](https://github.com/prisma/graphqlgen) to fix this issue with code generation, PureScript GraphQL makes use of PureScripts unique type system (especially row types) to ensure typesafety across the whole codebase. In PureScript GraphQL types of resolvers are automatically infered from the fields return type and arguments.
57+PureScript is a powerful statically typed functional programming language.
58+The static type system of PureScript pairs well with GraphQL since we can enforce that the application code actually returns the data that the API level needs at compile time.
59+In comparison, GraphQL.js also checks the values of all leaf types at runtime but for many bugs this might already be to late.
60+GraphQL.js also comes with Flow and TypeScript types.
61+Unfortunately neither the Flow type system nor the TypeScript type system is strong enough to express the complex raltionships between types in GraphQL schemas.
62+This leaves the resolvers untyped.
63+The resovlers become a source of errors since implementing resolvers is the bread and butter of GraphQL APIs.
64+While there are [effords in the community](https://github.com/graphql-nexus/nexus) to fix this issue with code generation, PureScript GraphQL makes use of PureScripts unique type system (especially row types) to ensure typesafety across the whole codebase.
65+In PureScript GraphQL, the types of resolvers are automatically infered from the fields return type and arguments.
2466
25−While modern async JavaScript is certainly way more fun to write than the infamous callback hell of good old ES5, there are still many patterns of functional programming that are helpful when writing the resolvers.
67+While modern async JavaScript is certainly way more fun to write than the infamous callback hell of common ES5, there are still many patterns of functional programming that are helpful when writing the resolvers.
68+Attempts of the JavaScript and TypeScript community to bring functional concepts to these languages are admireable but result in dramatic readability tradeoffs.
69+The simple lack of language features like generalised `do`-notation, auto-currying, a compose operator and pattern matching make the introduced features unattractive and a dedicated library to wrap GraphQL.js (similar to how PureScript v1 wraps GraphQL.js) would be needed to at least remove constant type conversion (e.g. between `null` and `Maybe`).
70+PureScript solves this with a compile step and this library now also allows the written PureScript code to make use of even more powerful concepts like monad transformers.
2671
2772## How to make the most of this tutorial
2873
29−To make the most out of this tutorial I would highly recommend to type the code into the editor instead of just copy-pasting. This tutorial attempts to provide small enough bits to make you follow along. You can find a running version of this tutorial's codebase in the [PureScript GraphQL example repository](https://github.com/hendrikniemann/purescript-graphql-example).
74+To make the most out of this tutorial I would highly recommend to type the code into the editor instead of just copy-pasting.
75+This tutorial attempts to provide small enough bits to make you follow along.
76+You can find a running version of this tutorial's codebase in the [PureScript GraphQL example repository](https://github.com/hendrikniemann/purescript-graphql-example).
3077
31−When you get stuck set yourself a time to try and resolve the problem on your own. If your are not able to solve the problem without help I would recommend the [functional programming Slack community](https://fpchat-invite.herokuapp.com/). The PureScript community is very active and beginner friendly. The _purescript-beginner_ slack channel is the best place to get quick help.
78+When you get stuck, set yourself a time frame to try and resolve the problem on your own.
79+If your are not able to solve the problem without help I would recommend the [functional programming Slack community](https://fpchat-invite.herokuapp.com/).
80+The PureScript community is very active and beginner friendly.
81+The _purescript-beginner_ slack channel is the best place to get quick help.
82+You can also reach out directly to me on this slack using my handle _hendrikniemann_.
docs/_sidebar.md+7−5
@@ -1,8 +1,10 @@
1+- [Introduction](README.md)
2+- [What's new in v2?](version_2.md)
13- Tutorial
2−
3− - [Introduction](README.md)
4+ - [Intro To GraphQL](intro_to_graphql.md)
45 - [Getting Started](getting_started.md)
5− - [Schema and Execution](schema_and_execution.md)
66 - [Building the HTTP server](http_server.md)
7− - [GraphQL Type System](type_system.md)
8− - [The Execution Context](context.md)
7+- Reference
8+ - [Scalar Types](scalar_types.md)
9+ - [Object Types](object_types.md)
10+ - [Union Types and Interfaces](union_types.md)
docs/getting_started.md+165−32
@@ -1,64 +1,197 @@
11# Getting Started
22
3+The goal of this chapter is to setup a simple PureScript project that defines a simple GraphQL schema.
4+The GraphQL schema will contain exactly one query field and allows us to execute a _Hello World_ query: `{ hello }`.
5+
36## Initialising the project
47
5−We will begin in an empty folder and initialise a PureScript project using pulp. This will create a project skelleton and install the prelude and two additional packages.
8+We will begin in an empty folder and initialise a PureScript project using spago.
9+This will create a project skelleton and install the prelude package for us.
610
711```
8−pulp init
12+spago init
913```
1014
11−Let's verify that your installation works by running the initialised project using pulp. In the future this command will be the single command that we use to start our server but for now it should just print a string to the console and terminate.
15+Let's verify that your installation works by running the initialised project using spago.
16+In the future this command will be the single command that we use to start our HTTP server but for now it should just print a string to the console and terminate.
1217
1318```
14−pulp run
19+spago run
1520```
1621
1722## Installing PureScript dependencies
1823
19−Next, we will install some dependencies that we will be using in this tutorial. To create our GraphQL API we will of cause use the `purescript-graphql` package. The package contains all modules that we need to decribe a GraphQL Schema.
24+Next, we will install some dependencies that we will be using in the next step of this tutorial.
25+To create our GraphQL API we will of course use the one and only `graphql` package.
26+The package contains all modules that we need to decribe a GraphQL Schema and execute queries.
27+
28+GraphQL query results are encoded in JSON. We will need the packages `argonaut-core` and `argonaut-codecs` to deal with the result of the GraphQL execution.
29+
30+Last but not least, we also add some generally useful libraries: `maybe`, `either` and `ordered-collections`
31+
32+> **Note:**
33+> I have been asked why I am not using `purescript-simple-json`.
34+> To build the result, PureScript GraphQL makes heavy use of the combinators of Argonaut.
35+> Argonaut now offers a superset of the operations in simple-json with the provided encoding and decoding type classes.
36+
37+!> Currently `purescript-graphql` is not part of the official package set and needs to be inserted manually into the packages.
38+This step won't be neccessary in the near future.
39+Adopt the `additions` variable in the `packages.dhall` file to install from the master branch:
40+
41+```dhall
42+let additions =
43+ { graphql =
44+ { dependencies =
45+ [ "argonaut"
46+ , "console"
47+ , "control"
48+ , "effect"
49+ , "enums"
50+ , "foldable-traversable"
51+ , "nullable"
52+ , "numbers"
53+ , "prelude"
54+ , "psci-support"
55+ , "record"
56+ , "spec"
57+ , "string-parsers"
58+ ]
59+ , repo = "https://github.com/hendrikniemann/purescript-graphql.git"
60+ , version = "master"
61+ }
62+ }
63+```
2064
21−The `purescript-aff` package defines the `Aff` monad. The `Aff` monad is used to describe asynchronious effects. When writing APIs we usually deal with a lot of asynchronious IO (read and write). For example we might want to read records from a database and then return them to the client.
65+To install all the purescript dependencies you can simply go ahead and run this command in your project directory.
2266
23−GraphQL itself does not specify the transportation layer of the client server communication. In our case we will simply go with HTTP - the most common protocol to transport GraphQL queries and responses. The `purescript-httpure` package will help us build a web server that can respond to HTTP post requests that contain a GraphQL query. PureScript GraphQL does not support subscriptions yet, otherwise we would also need to provide a technology that allows the server to _push_ data to the client (e.g. Web Sockets). GraphQL query results are encoded in JSON. We will need the packages `purescript-argonaut-core` and `purescript-argonaut-codecs` simply to deal with the payloads of the HTTP request and reponse.
67+```
68+spago install graphql argonaut maybe either ordered-collections
69+```
2470
25−We will get to know all of these packages in the following chapters. Don't feel lost! To install all the purescript dependencies you can simply go ahead and run this command in your project directory.
71+## Building the first schema
2672
73+Now we can start editing the `src/Main.purs` file in the project.
74+We will start with some imports.
75+The `GraphQL.Type` module contains functions and operators to construct GraphQL schemas.
76+I like to import the module under a qualifier since the exposed functions have quite generic names.
77+For convenience we also import two operators `(:>)` and `(!>)`.
78+They are used to build object types.
79+
80+```purescript
81+import Data.Maybe (Maybe(..))
82+import GraphQL.Type ((.>), (!>))
83+import GraphQL.Type as GraphQL
84+import GraphQL.Type.Scalar as Scalar
2785```
28−bower install --save purescript-graphql purescript-aff purescript-httpure purescript-argonaut-core purescript-argonaut-codecs
86+
87+Now, let's construct a simple schema:
88+
89+```purescript
90+schema :: GraphQL.Schema Effect Unit
91+schema = GraphQL.Schema { query: ?query, mutation: Nothing }
2992```
3093
31−In this tutorial we don't want to deal with the setup of a real database. Instead we will simply store the application state in memore using a reference to a store datastrucure. `purescript-ref` lets us work with mutable data in a monadic way. In a real project you would use a different package to connect to your database. This means these packages are just for the sake of this tutorial and you can uninstall them once you have connected a different data source.
94+`Schema` takes two types:
95+
96+- The context monad that we use to run our computations.
97+ I have simply chosen Effect because we already have it in scope and we want to eventually use the schema in the `main` function.
98+- The root type of the schema.
99+ A schema accepts a root value that is passed into all root resolvers as a parent value.
100+ While there are use cases for this, I seldomly use this functionality.
101+ Therefore we can just use the `Unit` type and indicate that we don't want to pass anything into these resolvers for now.
102+
103+Now you should see a type error, telling us about the type of the typed hole:
32104
33105```
34−bower install --save purescript-refs purescript-uuid
106+ Hole 'query' has the inferred type
107+
108+ ObjectType Effect Unit
35109```
36110
37−## Installing JavaScript dependencies
111+Let's build an object type that fits into the typed hole!
38112
39−Unfortunately PureScript uses _Bower_ to distribute packages, while all JavaScript dependencies are distributed via NPM these days. This means your PureScript dependencies cannot install their JavaScript dependencies automatically. The fastest way to install the JavaScript dependencies for this tutorial is to create a `package.json` file in your project directory with the following content:
113+```purescript
114+queryType :: GraphQL.ObjectType Effect Unit
115+queryType = GraphQL.objectType "Query"
116+```
40117
41−```json
42−{
43− "name": "purescript-graphql-example",
44− "version": "1.0.0",
45− "dependencies": {
46− "graphql": "^14.0.2",
47− "uuid": "^3.3.2",
48− "uuid-validate": "0.0.3"
49− }
50−}
118+Great, we now have a simple object type without fields.
119+Technically this is illegal in GraphQL.
120+We should quickly add a field to the object type.
121+As explained in the introduction to this chapter we want to execute a single query: `{ hello }`.
122+The result of the query should always be `{"data":{"hello":"world"}}`.
123+As we are returning a string from the _hello_ field, we chose the `string` scalar.
124+`GraphQL.Type.Scalar` contains all the standards scalars that the [GraphQL specification](http://spec.graphql.org/June2018/#sec-Scalars) defines.
125+
126+```purescript
127+helloField :: GraphQL.Field Effect String () ()
128+helloField = GraphQL.field "hello" Scalar.string
51129```
52130
53−Now all you have to do is run `npm install` in your console and you should be good to go! Again, feel free to remove the _UUID_ dependencies when you no longer make use of the `purescript-uuid` package in the future. Your project directory should now contain the following files and folders:
131+If we would add the field to the query type, we would encounter a type error because our field expects a string as the root value.
132+It is not easy to to make out which type above is the root value type but below we will see that we will almost never deal with these types explicitly again.
133+A field without a resolver just passes through the parent value.
134+Let's add a resolver that takes a unit parent value and returns the string "world" inside of the effect monad.
135+
136+```purescript
137+helloField :: GraphQL.Field Effect Unit () ()
138+helloField =
139+ GraphQL.withResolver
140+ (GraphQL.field "hello" Scalar.string)
141+ (\args parent -> pure "world")
142+```
143+
144+...and add the field to the query type...
54145
146+```purescript
147+queryType :: GraphQL.ObjectType Effect Unit
148+queryType = GraphQL.withField (GraphQL.objectType "Query") helloField
55149```
56−bower.json
57−bower_components
58−node_modules
59−output
60−package-lock.json
61−package.json
62−src
63−test
150+
151+Now, admittedly it is not the prettiest code to look at.
152+GraphQL APIs often consist of hundreds of types and thousands of fields.
153+Using the operators `.>` for `withField` and `!>` for `withResolver` we can shorten our code drastically and make inlining of the field more readable.
154+
155+```purescript
156+schema :: GraphQL.Schema Effect Unit
157+schema = GraphQL.Schema { query: queryType, mutation: Nothing }
158+
159+queryType :: GraphQL.ObjectType Effect Unit
160+queryType = GraphQL.objectType "Query"
161+ .> GraphQL.field "hello" Scalar.string
162+ !> (\args parent -> pure "world")
64163```
164+
165+## Executing the first query
166+
167+Now we want to make use of the `graphql` function to execute a query on the schema.
168+Import the function from `GraphQL` as well as the qualified `Map` and `stringify` to turn our result into a string:
169+
170+```purescript
171+import Data.Argonaut.Core (stringify)
172+import Data.Map as Map
173+import GraphQL (graphql)
174+```
175+
176+We can now execute the example query using this function.
177+
178+```purescript
179+graphql schema "{ hello }" Map.empty Nothing unit
180+```
181+
182+The `graphql` function expects a hell lot of parameters.
183+Parameter one and two should be familiar.
184+They are the schema that we have just built together and the query string that will be executed.
185+The last parameter `unit` is the root value that we have discussed earlier.
186+We will ignore the other two parameters for now and integrate the call into the `main` function.
187+
188+```purescript
189+main :: Effect Unit
190+main = do
191+ result <- graphql schema "{ hello }" Map.empty Nothing unit
192+ log $ stringify result
193+```
194+
195+We can run our program with `spago run` and should see the result in the console!
196+
197+In the next chapter we will hook up the query execution with an HTTP server to make GraphQL requests over the network.
docs/http_server.md+26−8
@@ -1,5 +1,22 @@
11# Building the HTTP server
22
3+GraphQL itself does not specify the transportation layer of the client server communication.
4+In our case we will simply go with HTTP - the most common protocol to transport GraphQL queries and responses.
5+The `purescript-httpure` package will help us build a web server that can respond to HTTP post requests that contain a GraphQL query.
6+PureScript GraphQL does not support subscriptions yet, otherwise we would also need to provide a technology that allows the server to _push_ data to the client (e.g. Web Sockets).
7+
8+> **Note:**
9+> We will create a HTTP server that roughly implements the [GraphQL over HTTP specification](https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md).
10+> To keep things simple we will leave out a few details, e.g. checking for the `Content-Type` header if the format is really JSON and responding to `GET` requests.
11+> But none of these things should be to hard to implement, they just clutter the examples below.
12+
13+## More dependencies
14+
15+The `purescript-aff` package defines the `Aff` monad.
16+The `Aff` monad is used to describe asynchronious effects.
17+When writing APIs we usually deal with a lot of asynchronious IO (read and write).
18+For example we might want to read records from a database and then return them to the client.
19+
320## GraphQL requests over HTTP POST
421
522As mentioned in the beginning we will be using `purescript-httpure` package to build a simple web server. For that we will again be editing our `src/Main.purs` file. If you want to go over this chapter rather quickly that is also fine since this toturial is not about building HTTP servers. Though, we will learn a lot about the parameters that can be contained in a GraphQL request and how we map them to the `graphql` function, that executes our queries.
@@ -23,13 +40,13 @@ main = HTTPure.serve 8080 router $ Console.log "Running server..."
2340The body of the request that our server accepts has to be in JSON format. Now that we have the body of the request we can try and parse it. The body _must_ contain the `query` variable and additionally may also contain `variables` and `operationName`. We will write a function `decodeParams` that takes a JSON value and returns a record containing the important GraphQL request parameters.
2441
2542```purescript
43+import Data.Either (Either)
2644import Data.Maybe (Maybe)
27−import Data.Argonaut.Core (Json)
28−import Data.Argonaut.Decode (decodeJson, (.:), (.:?))
45+import Data.Argonaut (Json, decodeJson, (.:), (.:?))
2946
3047type GraphQLParams =
3148 { query :: String
32− , variables :: Maybe Json
49+ , variables :: Maybe (Map String Json)
3350 , operationName :: Maybe String
3451 }
3552
@@ -37,17 +54,18 @@ decodeParams :: Json -> Either String GraphQLParams
3754decodeParams json = do
3855 obj <- decodeJson json
3956 query <- obj .: "query"
40− variables <- obj .:? "variables"
57+ variables <- map fromFoldableWithIndex <$>
58+ ((obj .:? "variables") :: Either String (Maybe (FO.Object Json)))
4159 operationName <- obj .:? "operationName"
42− pure { query, variables, operationName }
60+ pure $ { query, variables, operationName }
4361```
4462
45−Now it is time to change the router implementation to answer GraphQL requests that are sent over POST.
63+Now it is time to change the router implementation to answer GraphQL requests that are sent over `POST`.
64+Using pattern matching we can easily select requests that go to `POST /graphql` and only answer those.
4665
4766```purescript
4867import Data.Either (Either(..))
49−import Data.Argonaut.Core (stringify)
50−import Data.Argonaut.Parser (jsonParser)
68+import Data.Argonaut (stringify, jsonParser)
5169
5270router :: HTTPure.Request -> HTTPure.ResponseM
5371router { body, method: HTTPure.Post, path: [ "graphql" ] } =
docs/index.html+117−90
@@ -1,99 +1,126 @@
11<!DOCTYPE html>
22<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <title>purescript-graphql - A PureScript GraphQL Implementation</title>
6+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7+ <meta name="description" content="PureScript GraphQL implementation with end-to-end type checking." />
8+ <meta
9+ name="viewport"
10+ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
11+ />
12+ <link
13+ rel="stylesheet"
14+ href="//cdn.jsdelivr.net/npm/docsify-top-banner-plugin@latest/dist/style.css"
15+ />
16+ <link
17+ rel="stylesheet"
18+ href="https://unpkg.com/docsify/lib/themes/vue.css"
19+ />
20+ <link
21+ rel="stylesheet"
22+ href="https://cdn.jsdelivr.net/gh/tonsky/FiraCode@1.206/distr/fira_code.css"
23+ />
24+ <style>
25+ .constant {
26+ color: #00869c;
27+ }
328
4−<head>
5− <meta charset="UTF-8">
6− <title>purescript-graphql-example - Example purescript graphql app</title>
7− <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
8− <meta name="description" content="Example purescript graphql app">
9− <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
10− <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
11− <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tonsky/FiraCode@1.206/distr/fira_code.css">
12− <style>
13− .constant {
14− color: #00869C;
15− }
29+ code {
30+ font-family: Fira Code, Roboto Mono, Monaco, courier, monospace !important;
31+ }
1632
17− code {
18− font-family: Fira Code, Roboto Mono, Monaco, courier, monospace !important;
19− }
20− </style>
21−</head>
22−
23−<body>
24− <div id="app"></div>
25− <script>
26− window.$docsify = {
27− name: 'PureScript GraphQL',
28− repo: 'https://github.com/hendrikniemann/purescript-graphql',
29− loadSidebar: true
30− }
31− </script>
32− <script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
33− <script>
34− Prism.languages.purescript = {
35− comment: /--.*|{-[\s\S]*?-}/,
36− char: {
37− pattern: /'(?:[^\\'\r\n]|\\(?:[abfnrtv\\']|\d+|x[0-9a-fA-F]+))'/,
38− greedy: true
39− },
40− string: [
41− {
42− pattern: /"""[\s\S]*?"""/,
43− greedy: true
44− },
45− {
46− pattern: /"(?:[^\\"\r\n]|\\(?:[abfnrtv\\"]|\d+|x[0-9a-fA-F]+))*"/,
47− greedy: true
48− }
49− ],
50− import_statement: {
51− pattern: /^\s*import\s+[A-Z]\w*(?:\.[A-Z]\w*)*(?:\s+as\s+([A-Z]\w*)(?:\.[A-Z]\w*)*)?(?:\s+exposing\s+)?/m,
52− inside: {
53− keyword: /\b(?:import|as)\b/
33+ #TOPBANNER {
34+ padding: 0.4rem;
35+ padding-left: 300px;
36+ }
37+ @media screen and (max-width: 768px) {
38+ #TOPBANNER {
39+ padding-left: 0.4rem;
5440 }
55− },
56− module_definition: {
57− pattern: /^\s*module\s+[A-Z]\w*(?:\.[A-Z]\w*)*\s+(?:\(\s*\w+\s*(?:\s*,\s*\w+)*\))?\s+where/m,
58− inside: {
59− keyword: /\b(?:module|where)\b/
60− }
61− },
62− keyword: /\b(?:case|else|if|in|infixl|infixr|let|of|then|type|newtype|data|where|class|instance|kind|forall)\b/,
63− number: /\b(?:\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b/i,
64− operator: /[+\-/*=.$<>:&|^?%#@~!]{2,}|[+\-/*=$<>:&|^?%#@~!]/,
65− hvariable: /\b(?:[A-Z]\w*\.)*[a-z]\w*\b/,
66− constant: /\b(?:[A-Z]\w*\.)*[A-Z]\w*\b/,
67− punctuation: /[{}[\]|(),.:]/
68− };
41+ }
42+ </style>
43+ </head>
6944
70− Prism.languages.graphql = {
71− 'comment': /#.*/,
72− 'string': {
73− pattern: /"(?:\\.|[^\\"\r\n])*"/,
74− greedy: true
75− },
76− 'number': /(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,
77− 'boolean': /\b(?:true|false)\b/,
78− 'variable': /\$[a-z_]\w*/i,
79− 'directive': {
80− pattern: /@[a-z_]\w*/i,
81− alias: 'function'
82− },
83− 'attr-name': /[a-z_]\w*(?=\s*:)/i,
84− 'keyword': [
85− {
86− pattern: /(fragment\s+(?!on)[a-z_]\w*\s+|\.{3}\s*)on\b/,
87− lookbehind: true
45+ <body>
46+ <div id="app"></div>
47+ <script>
48+ window.$docsify = {
49+ name: "PureScript GraphQL",
50+ repo: "https://github.com/hendrikniemann/purescript-graphql",
51+ loadSidebar: true,
52+ topBanner: {
53+ content: "Looking for v1 docs? [Legacy Documentation](/v1/)",
54+ position: "relative",
55+ zIndex: -1,
56+ },
57+ };
58+ </script>
59+ <script src="https://unpkg.com/docsify/lib/docsify.min.js"></script>
60+ <script src="https://cdn.jsdelivr.net/npm/docsify-top-banner-plugin@latest/dist/index.js"></script>
61+ <script>
62+ Prism.languages.purescript = {
63+ comment: /--.*|{-[\s\S]*?-}/,
64+ char: {
65+ pattern: /'(?:[^\\'\r\n]|\\(?:[abfnrtv\\']|\d+|x[0-9a-fA-F]+))'/,
66+ greedy: true,
8867 },
89− /\b(?:query|fragment|mutation|type|enum|schema)\b/
90− ],
91− 'operator': /!|=|\.{3}/,
92− 'punctuation': /[!(){}\[\]:=,]/,
93− 'constant': /ID|String|Int|Float|Boolean/,
94− };
95− </script>
96− <script src="//unpkg.com/prismjs/components/prism-json.min.js"></script>
97−</body>
68+ string: [
69+ {
70+ pattern: /"""[\s\S]*?"""/,
71+ greedy: true,
72+ },
73+ {
74+ pattern: /"(?:[^\\"\r\n]|\\(?:[abfnrtv\\"]|\d+|x[0-9a-fA-F]+))*"/,
75+ greedy: true,
76+ },
77+ ],
78+ import_statement: {
79+ pattern: /^\s*import\s+[A-Z]\w*(?:\.[A-Z]\w*)*(?:\s+as\s+([A-Z]\w*)(?:\.[A-Z]\w*)*)?(?:\s+exposing\s+)?/m,
80+ inside: {
81+ keyword: /\b(?:import|as)\b/,
82+ },
83+ },
84+ module_definition: {
85+ pattern: /^\s*module\s+[A-Z]\w*(?:\.[A-Z]\w*)*\s+(?:\(\s*\w+\s*(?:\s*,\s*\w+)*\))?\s+where/m,
86+ inside: {
87+ keyword: /\b(?:module|where)\b/,
88+ },
89+ },
90+ keyword: /\b(?:case|else|if|in|infixl|infixr|let|of|then|type|newtype|data|where|class|instance|kind|forall|do|ado)\b/,
91+ number: /\b(?:\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b/i,
92+ operator: /[+\-/*=.$<>:&|^?%#@~!]{2,}|[+\-/*=$<>:&|^?%#@~!]/,
93+ hvariable: /\b(?:[A-Z]\w*\.)*[a-z]\w*\b/,
94+ constant: /\b(?:[A-Z]\w*\.)*[A-Z]\w*\b/,
95+ punctuation: /[{}[\]|(),.:]/,
96+ };
9897
98+ Prism.languages.graphql = {
99+ comment: /#.*/,
100+ string: {
101+ pattern: /"(?:\\.|[^\\"\r\n])*"/,
102+ greedy: true,
103+ },
104+ number: /(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,
105+ boolean: /\b(?:true|false)\b/,
106+ variable: /\$[a-z_]\w*/i,
107+ directive: {
108+ pattern: /@[a-z_]\w*/i,
109+ alias: "function",
110+ },
111+ "attr-name": /[a-z_]\w*(?=\s*:)/i,
112+ keyword: [
113+ {
114+ pattern: /(fragment\s+(?!on)[a-z_]\w*\s+|\.{3}\s*)on\b/,
115+ lookbehind: true,
116+ },
117+ /\b(?:query|fragment|mutation|type|enum|schema|union|interface)\b/,
118+ ],
119+ operator: /!|=|\.{3}/,
120+ punctuation: /[!(){}\[\]:=,]/,
121+ constant: /ID|String|Int|Float|Boolean/,
122+ };
123+ </script>
124+ <script src="//unpkg.com/prismjs/components/prism-json.min.js"></script>
125+ </body>
99126</html>
docs/intro_to_graphql.mdnew file+43
@@ -0,0 +1,43 @@
1+# A functional programmers guide to GraphQL
2+
3+> In this guide we will have a look at GraphQL coming from a functional programming background.
4+> It is very brief because I believe the best way of learning GraphQL is through building and exploring.
5+> Instead, this section is supposed to teach you just enough to get started using PureScript GraphQL
6+
7+GraphQL is a query language for APIs that expose graph-like data structures.
8+A GraphQL API exposes all available data and operations in a giant graph.
9+The API consumer then uses GraphQL to select a subset of the data (a sub-graph).
10+Compared to other (graph) query languages, e.g. Cypher for Neo4j or SQL, GraphQL is a rather weak language that leaves room for custom implementation specific logic.
11+A GraphQL query mostly only consists of _selection sets_, _fields_ and _field arguments_.
12+
13+## GraphQL schema and type system
14+
15+Every GraphQL endpoint exposes exactly one schema.
16+The schema is a description of which queries can be executed on the GraphQL API.
17+GraphQL has a simple type system to describe this structure.
18+This type system features scalars for promitive types, object types for record structures and union types for sum types.
19+
20+## GraphQL resolver model
21+
22+There are many ways how a GraphQL query can be translated into a corresponding result.
23+PureScript GraphQL uses the well established resolver model.
24+In the resolver model, every field is paired with a function that describes how the provided field arguments together with the parent value form the field's value.
25+In PureScript GraphQL, a field can also perform some form of side effects, if the schema allows for it.
26+Let's look at some simple resolver examples:
27+
28+```purescript
29+-- Root resolver loads row from database
30+todo :: { id :: String } -> Unit -> Aff (Todo { title :: String, isCompleted :: Boolean })
31+todo args parent = loadTodoById args.id
32+
33+-- Field with no arguments resolves to parent field
34+isCompleted :: {} -> Todo { title :: String, isCompleted :: Boolean } -> Aff String
35+isCompleted args (Todo { isCompleted }) = pure isCompleted
36+```
37+
38+## GraphQL over HTTP
39+
40+The GraphQL specification itself deliberately leaves out specifics about the transport layer.
41+GraphQL queries can be sent via HTTP, websockets or any other text format imaginable.
42+On the web, we usually find GraphQL servers that use HTTP for queries and mutations and websockets for subscriptions.
43+PureScript GraphQL does not provide transport layer functionality, but we are going to build an HTTP server in one of the chapters of this documentation.
docs/object_types.mdnew file+82
@@ -0,0 +1,82 @@
1+# Obejct Types
2+
3+## About object types
4+
5+Object types are used to represent complex data structures.
6+Objects map very closely to records or structures in other programming languages.
7+In SDL, object types are defined in a way that is very similar to PureScript records or TypeScript objects:
8+
9+```graphql
10+type Todo {
11+ id: ID!
12+ title: String!
13+ createdAt: DateTime!
14+ completedAt: DateTime
15+}
16+```
17+
18+An object type on the API level describes an offer to the client.
19+Which fields are returned to the client depends on the query.
20+
21+## Creating an object type
22+
23+Imagine we want to build a simple object type for the following record type in PureScript:
24+
25+```purescript
26+type Todo =
27+ { id :: Int
28+ , title :: String
29+ , createdAt :: DateTime
30+ , completedAt :: Maybe DateTime
31+ }
32+```
33+
34+We start with an empty object type by giving it a name:
35+
36+```purescript
37+todoType :: GraphQL.ObjectType Context Todo
38+todoType = GraphQL.objectType "Todo"
39+```
40+
41+In the type signature, we define the context in which our GraphQL operations are executed.
42+This can be any monad with a `MonadError Error` instance, like `Aff`, `Effect`, `Either Error`, etc.
43+Obviously, if we want to run side effects, we need an appropriate monad.
44+I recommend to create a fitting monad transformer stack and exporting the type to your object types.
45+For now we can use `Effect`, which allows us to run simple effects like logging.
46+
47+The second type is the root value (or sometimes called parent value) type.
48+In this case, we want to build an object type for the `Todo` type above.
49+Object types don't contain any values themselves, they expose subfields that can be selected by the API consumer.
50+Their purpose is to group values in a single structure (in PureScript often referred to as Sum Types).
51+An object type without any fields is not of much use and in fact it is forbidden in GraphQL.
52+An object type must at least have one field.
53+
54+We can define fields on object types by using the `withField` function.
55+
56+```purescript
57+todoType :: GraphQL.ObjectType Effect Todo
58+todoType =
59+ GraphQL.withField
60+ (GraphQL.objectType "Todo")
61+ (GraphQL.field "id" GraphQL.id)
62+
63+-- or in infix notation
64+todoType :: GraphQL.ObjectType Effect Todo
65+todoType =
66+ GraphQL.objectType "Todo" `GraphQL.withField` GraphQL.field "id" GraphQL.id
67+
68+-- or even better with the DSL operator imported from GraphQL
69+todoType :: GraphQL.ObjectType Effect Todo
70+todoType = GraphQL.objectType "Todo"
71+ .> GraphQL.field "id" GraphQL.id
72+```
73+
74+We can add descriptions to objects and fields.
75+These descriptions are available via _introspection_ a way to query an API about its structure and data offerings.
76+
77+```purescript
78+todoType :: GraphQL.ObjectType Effect Todo
79+todoType = GraphQL.objectType "Todo"
80+ :> "A todo holds information about a task and its completion status"
81+ .> GraphQL.field "id" GraphQL.id
82+```
docs/scalar_types.mdnew file+92
@@ -0,0 +1,92 @@
1+# Scalar Types
2+
3+## Leaf Types
4+
5+In GraphQL, Leaf Types are types that turn into a specific value and have no connections to other types (other than their parent node).
6+There are two GraphQL kinds that can produce leaf types: The Scalar and the Enumeration.
7+Enum types are used for types that have a finite set of values and serialize by mapping to a finite set of JSON string values.
8+Scalar types, on the other hand, can serialize to any JSON value.
9+This includes JSON lists and maps, but usually scalars should use the JSON primitive types for representation: String, Number, Boolean.
10+
11+## Built in Scalar Types
12+
13+The GraphQL Specification lists five scalar types, that need to be supported by every GraphQL implementation.
14+These scalars are probably enough to get you started in your project.
15+
16+- The `Int` scalar is used for [natural numbers in the Int32 range](http://spec.graphql.org/June2018/#sec-Int).
17+- The `Float` type represents [signed double‐precision fractional values](http://spec.graphql.org/June2018/#sec-Float).
18+- The `String` scalar represents [UTF-8 encoded strings](http://spec.graphql.org/June2018/#sec-String).
19+- The `Boolean` scalar represents [boolean logic truth values](http://spec.graphql.org/June2018/#sec-Boolean).
20+- And finally the `ID` scalar is used for [unique identifiers](http://spec.graphql.org/June2018/#sec-ID). It is always serialised as a JSON string, but can also accept integer values from client queries.
21+
22+PureScript GraphQL provides implementations for these scalars in the `GraphQL.Builtin.Scalar` module.
23+As GraphQL types are values in PureScript, they use lower case identifiers: `int`, `float`, `string`, `boolean` and `id`.
24+They are exported as well from the `GraphQL` main module.
25+
26+## Defining custom Scalar Types
27+
28+Sometimes, the built in scalar types are not enough and you want to represent a custom type together with input validation.
29+One great example is the `DateTime` scalar.
30+
31+> **Note:**
32+> You can find the full code for this example [here](https://github.com/hendrikniemann/purescript-graphql-fullstack-example/blob/master/backend/src/Schema/DateTime.purs).
33+
34+The predefined scalars are using the `ScalarType` newtype to implement the serialization and deserialization logic.
35+We can do the same to provide our own custom scalars.
36+If we want to build a scalar that serializes `DateTime` from `Data.DateTime` into a string in ISO 8601 format (`YYYY-MM-DDTHH:mm:ss.SSSZ`), we have to provide two functions:
37+
38+- `parseDateTime` which takes a string and returns either an error message or a valid `DateTime`.
39+- `formatDateTime` which turns a `DateTime` into a string.
40+
41+Using `Data.Formatter.DateTime`, we can easily write these functions:
42+
43+```purescript
44+parseDateTime :: String -> Either String DateTime
45+parseDateTime = unformat dateFormat
46+
47+formatDateTime :: DateTime -> String
48+formatDateTime = format dateFormat
49+
50+dateFormat ∷ Formatter
51+dateFormat = parseFormatString "YYYY-MM-DDTHH:mm:ss.SSSZ" # unsafePartial fromRight
52+```
53+
54+With these two helper functions we can now implement the functions needed by the scalar:
55+
56+### `parseLiteral`
57+
58+`parseLiteral` is called when the scalar is used in an argument in a query and the value is supplied inline as a literal.
59+Here we have to deal with the different literal types that exist in GraphQL.
60+In our case we only want to accept `StringValueNode`s and error on everything else.
61+We can then parse the value using the `parseDateTime` function above.
62+
63+```purescript
64+parseLiteral (AST.StringValueNode { value }) = parseDateTime value
65+parseLiteral _ = Left "Expected string literal node for input type date time."
66+```
67+
68+> Usually types only work for a single type of literal but it is totally possible to parse different types of literals if you want to do so.
69+> It can also be an opportunity to implement more specific error messages.
70+
71+### `parseValue`
72+
73+`parseValue` is called whenever a variable of our scalar type is supplied.
74+In this case we have to react to a JSON value. This is easy with _Argonaut_:
75+
76+```purescript
77+parseValue = Json.caseJsonString (Left "Dates must be supplied as ISO strings.") parseDateTime
78+```
79+
80+### `serialize`
81+
82+In `serialize` we have to do the opposite:
83+Turn a `DateTime` value into a JSON value.
84+Again, we are using _Argonaut_ and our helper function `formatDateTime` to compose the final function.
85+
86+```purescript
87+serialize = formatDateTime >>> Json.fromString
88+```
89+
90+!> Scalars in PureScript are designed to be as typesafe and pure as possible.
91+Therefore `serialize` is not allowed to have side effects or return an error.
92+All potential errors must be dealt with in the field resolver.
docs/union_types.mdnew file+91
@@ -0,0 +1,91 @@
1+# Union Types and Interfaces
2+
3+## Sum types in GraphQL
4+
5+Sometimes in our API, we want to return a values of different types.
6+Imagine the following example:
7+In a Twitter-like social media app, we have a stream of posts.
8+Posts can contain some media, either a link/url, an image or a video.
9+
10+In PureScript we could model it like this:
11+
12+```purescript
13+newtype Post = Post { id :: Int, body :: String, media :: Maybe Media }
14+
15+data Media
16+ = Link { url :: String, title :: String }
17+ | Image { url :: String, altText :: Maybe String }
18+ | Video { url :: String, length :: Int }
19+```
20+
21+In GraphQL, we can use the union type to create a sum type of object types.
22+
23+```graphql
24+type Post {
25+ id: ID!
26+ body: String!
27+ media: Media
28+}
29+
30+type Link {
31+ url: String!
32+ title: String!
33+}
34+
35+type Image {
36+ url: String!
37+ altText: String
38+}
39+
40+type Video {
41+ url: String!
42+ length: Int!
43+}
44+
45+union Media = Link | Image | Video
46+```
47+
48+An alternative way to create sum types are `Variant`s.
49+Variants use row types instead and let us create more reusable functions.
50+Variants also allow for type level programming.
51+
52+```purescript
53+type MediaVariant = Variant
54+ ( link :: { url :: String, title :: String }
55+ , image :: { url :: String, altText :: Maybe String }
56+ , video :: { url :: String, length :: Int }
57+ )
58+```
59+
60+## Using union types in PureScript GraphQL
61+
62+Variant types are not that easy to use, because we have to use `Proxy` to handle type level strings in our code.
63+But they allow PureScript GraphQL to generate a Variant type, when we supply a record of object types for the union type.
64+To build a union type in PureScript GraphQL, we use the `union` function from `GraphQL.Type` (here imported as `GQL`):
65+
66+```purescript
67+-- This assumes you already built the following object types:
68+-- linkType :: GQL.ObjectType Context { url :: String, title :: String }
69+-- imageType :: GQL.ObjectType Context { url :: String, altText :: Maybe String }
70+-- videoType :: GQL.ObjectType Context { url :: String, length :: Int }
71+
72+mediaType :: GQL.UnionType Context MediaVariant
73+mediaType = GQL.union "Media" { link: linkType, image: imageType, video: videoType }
74+```
75+
76+Notice how the record type used in the definition is very similar to the variant type.
77+
78+```purescript
79+record :: Record
80+ ( link :: GQL.ObjectType Context { url :: String, title :: String }
81+ , image :: GQL.ObjectType Context { url :: String, altText :: Maybe String }
82+ , video :: GQL.ObjectType Context { url :: String, length :: Int }
83+ )
84+record = { link: linkType, image: imageType, video: videoType }
85+
86+type MediaVariant = Variant
87+ ( link :: { url :: String, title :: String }
88+ , image :: { url :: String, altText :: Maybe String }
89+ , video :: { url :: String, length :: Int }
90+ )
91+```
docs/v1/.nojekyllnew file

No changes to the content.

docs/v1/README.mdnew file+31
@@ -0,0 +1,31 @@
1+# Introduction
2+
3+## About PureScript GraphQL
4+
5+This is a tutorial on Purescript GraphQL (`purescript-graphql`), a wrapper for PureScript around the JavaScript GraphQL reference implementation [GraphQL.js](https://github.com/graphql/graphql-js) (`graphql-js`) initially developed by Facebook. The JavaScript ecosystem is definitely the most prominent one around GraphQL (even though historically neither the first client nor the first server implementation was written in JavaScript). With PureScript we can make use of the JavaScript ecosytem while at the same time enjoying typesafety and all the programming patterns we love (and hate) from pure functional programming.
6+
7+To make the use of PureScript GraphQL more idomatic it does a few type conversions. While GraphQL.js works with JavaScript's Promises, the PureScript ecosystem favours the Aff monad. Furthermore nullable values are converted to `Maybe`s. These conversions come at a price but should still be worth it compared to a full PureScript GraphQL implementation since the whole parsing and execution engine is written in JavaScript and should be very fast.
8+
9+## Prerequisites
10+
11+This tutorial assumes that you are already familiar with some PureScript and the basics of GraphQL. You can learn the basics of GraphQL on the offical [GraphQL website](http://graphql.org). If you are already very familiar with GraphQL and the JavaScript implementation this tutorial can also be a nice comparison between the languages.
12+
13+For this tutorial we will be using PureScript 0.12, Pulp and Bower. You can find out how to install them on the [PureScript website](http://www.purescript.org/). All three of them need [Node.js](http://nodejs.org) and we will also make use of NPM, that comes with Node.js, to install some JavaScript dependencies.
14+
15+To try out and execute our GraphQL queries we will need a GraphQL client. Theoretically you can use CURL or Postman but I recommend the [GraphQL Playground](https://github.com/prisma/graphql-playground).
16+
17+## Why GraphQL
18+
19+GraphQL is a statically typed query language and since this is a tutorial for PureScript we don't have to discuss the benefits of strong type systems. GraphQL lets us create powerful APIs that are fun to build and fun to use. GraphQL APIs are easy to extend because if we follow a few rules we can make changes without breaking our clients.
20+
21+## Why PureScript
22+
23+PureScript is a powerful statically typed functional programming language. The static type system of PureScript pairs well with GraphQL since we can enforce that the application code actually returns the data that the API level needs at compile time. In comparison, GraphQL.js also checks the values of all leaf types at runtime but for many bugs this might already be to late. GraphQL.js also comes with Flow types. Unfortunately the Flow type system is not strong enough to express the complex raltionships between the GraphQL types. This leaves the resolvers untyped - the main source of errors since implementing resolvers is the bread and butter of GraphQL APIs. While there are [effords in the community](https://github.com/prisma/graphqlgen) to fix this issue with code generation, PureScript GraphQL makes use of PureScripts unique type system (especially row types) to ensure typesafety across the whole codebase. In PureScript GraphQL types of resolvers are automatically infered from the fields return type and arguments.
24+
25+While modern async JavaScript is certainly way more fun to write than the infamous callback hell of good old ES5, there are still many patterns of functional programming that are helpful when writing the resolvers.
26+
27+## How to make the most of this tutorial
28+
29+To make the most out of this tutorial I would highly recommend to type the code into the editor instead of just copy-pasting. This tutorial attempts to provide small enough bits to make you follow along. You can find a running version of this tutorial's codebase in the [PureScript GraphQL example repository](https://github.com/hendrikniemann/purescript-graphql-example).
30+
31+When you get stuck set yourself a time to try and resolve the problem on your own. If your are not able to solve the problem without help I would recommend the [functional programming Slack community](https://fpchat-invite.herokuapp.com/). The PureScript community is very active and beginner friendly. The _purescript-beginner_ slack channel is the best place to get quick help.
docs/v1/_sidebar.mdnew file+8
@@ -0,0 +1,8 @@
1+- Tutorial
2+
3+ - [Introduction](v1/README.md)
4+ - [Getting Started](v1/getting_started.md)
5+ - [Schema and Execution](v1/schema_and_execution.md)
6+ - [Building the HTTP server](v1/http_server.md)
7+ - [GraphQL Type System](v1/type_system.md)
8+ - [The Execution Context](v1/context.md)
docs/context.md → docs/v1/context.mdrenamed

The content is the same.

docs/v1/getting_started.mdnew file+64
@@ -0,0 +1,64 @@
1+# Getting Started
2+
3+## Initialising the project
4+
5+We will begin in an empty folder and initialise a PureScript project using pulp. This will create a project skelleton and install the prelude and two additional packages.
6+
7+```
8+pulp init
9+```
10+
11+Let's verify that your installation works by running the initialised project using pulp. In the future this command will be the single command that we use to start our server but for now it should just print a string to the console and terminate.
12+
13+```
14+pulp run
15+```
16+
17+## Installing PureScript dependencies
18+
19+Next, we will install some dependencies that we will be using in this tutorial. To create our GraphQL API we will of cause use the `purescript-graphql` package. The package contains all modules that we need to decribe a GraphQL Schema.
20+
21+The `purescript-aff` package defines the `Aff` monad. The `Aff` monad is used to describe asynchronious effects. When writing APIs we usually deal with a lot of asynchronious IO (read and write). For example we might want to read records from a database and then return them to the client.
22+
23+GraphQL itself does not specify the transportation layer of the client server communication. In our case we will simply go with HTTP - the most common protocol to transport GraphQL queries and responses. The `purescript-httpure` package will help us build a web server that can respond to HTTP post requests that contain a GraphQL query. PureScript GraphQL does not support subscriptions yet, otherwise we would also need to provide a technology that allows the server to _push_ data to the client (e.g. Web Sockets). GraphQL query results are encoded in JSON. We will need the packages `purescript-argonaut-core` and `purescript-argonaut-codecs` simply to deal with the payloads of the HTTP request and reponse.
24+
25+We will get to know all of these packages in the following chapters. Don't feel lost! To install all the purescript dependencies you can simply go ahead and run this command in your project directory.
26+
27+```
28+bower install --save purescript-graphql purescript-aff purescript-httpure purescript-argonaut-core purescript-argonaut-codecs
29+```
30+
31+In this tutorial we don't want to deal with the setup of a real database. Instead we will simply store the application state in memore using a reference to a store datastrucure. `purescript-ref` lets us work with mutable data in a monadic way. In a real project you would use a different package to connect to your database. This means these packages are just for the sake of this tutorial and you can uninstall them once you have connected a different data source.
32+
33+```
34+bower install --save purescript-refs purescript-uuid
35+```
36+
37+## Installing JavaScript dependencies
38+
39+Unfortunately PureScript uses _Bower_ to distribute packages, while all JavaScript dependencies are distributed via NPM these days. This means your PureScript dependencies cannot install their JavaScript dependencies automatically. The fastest way to install the JavaScript dependencies for this tutorial is to create a `package.json` file in your project directory with the following content:
40+
41+```json
42+{
43+ "name": "purescript-graphql-example",
44+ "version": "1.0.0",
45+ "dependencies": {
46+ "graphql": "^14.0.2",
47+ "uuid": "^3.3.2",
48+ "uuid-validate": "0.0.3"
49+ }
50+}
51+```
52+
53+Now all you have to do is run `npm install` in your console and you should be good to go! Again, feel free to remove the _UUID_ dependencies when you no longer make use of the `purescript-uuid` package in the future. Your project directory should now contain the following files and folders:
54+
55+```
56+bower.json
57+bower_components
58+node_modules
59+output
60+package-lock.json
61+package.json
62+src
63+test
64+```
docs/v1/http_server.mdnew file+62
@@ -0,0 +1,62 @@
1+# Building the HTTP server
2+
3+## GraphQL requests over HTTP POST
4+
5+As mentioned in the beginning we will be using `purescript-httpure` package to build a simple web server. For that we will again be editing our `src/Main.purs` file. If you want to go over this chapter rather quickly that is also fine since this toturial is not about building HTTP servers. Though, we will learn a lot about the parameters that can be contained in a GraphQL request and how we map them to the `graphql` function, that executes our queries.
6+
7+GraphQL requests are usually transmitted over HTTP. The GraphQL language specification does not specify the protocol but HTTP is the easiest way for client-server communication when building web applications. Our GraphQL server should be able to respond to POST requests. Some GraphQL servers also accept GET requests but we will keep it simple and only support POST requests.
8+
9+To create a server we will start with the basic POST example from HTTPure.
10+
11+```purescript
12+import Effect.Console as Console
13+import HTTPure as HTTPure
14+
15+router :: HTTPure.Request -> HTTPure.ResponseM
16+router { body, method: HTTPure.Post } = HTTPure.ok body
17+router _ = HTTPure.notFound
18+
19+main :: HTTPure.ServerM
20+main = HTTPure.serve 8080 router $ Console.log "Running server..."
21+```
22+
23+The body of the request that our server accepts has to be in JSON format. Now that we have the body of the request we can try and parse it. The body _must_ contain the `query` variable and additionally may also contain `variables` and `operationName`. We will write a function `decodeParams` that takes a JSON value and returns a record containing the important GraphQL request parameters.
24+
25+```purescript
26+import Data.Maybe (Maybe)
27+import Data.Argonaut.Core (Json)
28+import Data.Argonaut.Decode (decodeJson, (.:), (.:?))
29+
30+type GraphQLParams =
31+ { query :: String
32+ , variables :: Maybe Json
33+ , operationName :: Maybe String
34+ }
35+
36+decodeParams :: Json -> Either String GraphQLParams
37+decodeParams json = do
38+ obj <- decodeJson json
39+ query <- obj .: "query"
40+ variables <- obj .:? "variables"
41+ operationName <- obj .:? "operationName"
42+ pure { query, variables, operationName }
43+```
44+
45+Now it is time to change the router implementation to answer GraphQL requests that are sent over POST.
46+
47+```purescript
48+import Data.Either (Either(..))
49+import Data.Argonaut.Core (stringify)
50+import Data.Argonaut.Parser (jsonParser)
51+
52+router :: HTTPure.Request -> HTTPure.ResponseM
53+router { body, method: HTTPure.Post, path: [ "graphql" ] } =
54+ case jsonParser body >>= decodeParams of
55+ Left error -> HTTPure.badRequest error
56+ Right { query, variables, operationName } -> do
57+ result <- graphql schema query unit context variables operationName
58+ HTTPure.ok $ stringify result
59+router _ = HTTPure.notFound
60+```
61+
62+This is it. Start the server with `pulp run` and connect to it using a desktop installation of [GraphQL Playground](https://github.com/prisma/graphql-playground) on `http://localhost:8080/graphql`. You should now be able to run the hello world query inside of playground.
docs/schema_and_execution.md → docs/v1/schema_and_execution.mdrenamed

The content is the same.

docs/type_system.md → docs/v1/type_system.mdrenamed

The content is the same.

docs/version_2.mdnew file+43
@@ -0,0 +1,43 @@
1+# What's new in Version 2 of PureScript GraphQL?
2+
3+PureScript GraphQL Version 2 is here.
4+Version 2 is a complete rewrite and has many breaking changes.
5+While version 1 can be considered stable thanks to the battle tested GraphQL.js library in the background, version 2 tries to actually build a PureScript implementation for GraphQL.
6+With version 1, you could build GraphQL servers with PureScript.
7+Now you can build GraphQL servers **in** PureScript.
8+But what does that even mean? We are no longer bound to the interface of a mutable object oriented language and instead use functional programming concepts to achieve similar effects.
9+
10+I am myself still learning these concepts one step at the time.
11+But I have gathered feedback from the community and came up with these interesting changes that let you dive fully into pure functional programming.
12+
13+## Free Choice of Execution Context
14+
15+This is the biggest change and pretty much the sole motivator for the rewrite.
16+The GraphQL result can now be calculated inside of the context of any monad (that supports errors).
17+Usually the execution of a schema is an effectful computation.
18+The user of the library is now completely free to use any effect monad of their choice as long as it provides a `MonadError Error` implementation (like e.g. `Aff` or `Effect`).
19+If the execution is completely pure one can even use `Either Error` to create side-effectless synchronious schemas.
20+But in practise our computations are not only effectful but also stateful.
21+Here we want to use a custom monad!
22+You can now build up any monad transformer stack and use it as the context of your GraphQL execution.
23+
24+Furthermore, context is no longer a mutable object being passed into every resolver.
25+Previously PureScript GraphQL followed GraphQL.js and allowed to pass in a context object into every resolver.
26+But we don't need that in PureScript GraphQL.
27+We have `StateT`.
28+In the later stages of this tutorial, I use a monad stack to inject a database connection and the ID of the currently authenticated user into every resolver.
29+
30+## List fields accept any Traversable
31+
32+Tired of arrays?
33+You prefer your good old `List`?
34+Or sometimes you just want to directly return a `Map` from a resolver?
35+No problem!
36+PureScript GraphQL will painlessly fold your data structure into a JSON array.
37+`Traversable` is needed to collect the results of the child resolvers into the context monad.
38+
39+## New functional DSL
40+
41+In PureScript GraphQL v2 we introduce a new embedded DSL to create GraphQL types.
42+All data structures used to create a schema are now plain immutable PureScript types, that can be combined and changed with the provided functions and operators.
43+This allows us to write interesting abstractions on top of PureScript GraphQL.
package-lock.json+736−2988
@@ -4,380 +4,173 @@
44 "lockfileVersion": 1,
55 "requires": true,
66 "dependencies": {
7− "ansi-align": {
8− "version": "2.0.0",
9− "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
10− "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
11− "dev": true,
12− "requires": {
13− "string-width": "^2.0.0"
14− }
15− },
16− "ansi-escapes": {
17− "version": "1.4.0",
18− "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
19− "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
20− "dev": true
21− },
22− "ansi-regex": {
23− "version": "2.1.1",
24− "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
25− "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
26− "dev": true
27− },
28− "ansi-styles": {
29− "version": "2.2.1",
30− "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
31− "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
7+ "@sindresorhus/is": {
8+ "version": "0.14.0",
9+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
10+ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
3211 "dev": true
3312 },
34− "anymatch": {
35− "version": "1.3.2",
36− "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
37− "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
13+ "@szmarczak/http-timer": {
14+ "version": "1.1.2",
15+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
16+ "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
3817 "dev": true,
3918 "requires": {
40− "micromatch": "^2.1.5",
41− "normalize-path": "^2.0.0"
19+ "defer-to-connect": "^1.0.1"
4220 }
4321 },
44− "arr-diff": {
45− "version": "2.0.0",
46− "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
47− "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
22+ "ansi-align": {
23+ "version": "3.0.0",
24+ "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
25+ "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==",
4826 "dev": true,
4927 "requires": {
50− "arr-flatten": "^1.0.1"
28+ "string-width": "^3.0.0"
5129 }
5230 },
53− "arr-flatten": {
54− "version": "1.1.0",
55− "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
56− "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
57− "dev": true
58− },
59− "arr-union": {
60− "version": "3.1.0",
61− "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
62− "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
63− "dev": true
64− },
65− "array-unique": {
66− "version": "0.2.1",
67− "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
68− "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
69− "dev": true
70− },
71− "assign-symbols": {
72− "version": "1.0.0",
73− "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
74− "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
75− "dev": true
76− },
77− "async-each": {
78− "version": "1.0.3",
79− "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
80− "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
81− "dev": true
82− },
83− "atob": {
84− "version": "2.1.2",
85− "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
86− "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
31+ "ansi-regex": {
32+ "version": "4.1.0",
33+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
34+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
8735 "dev": true
8836 },
89− "babel-polyfill": {
90− "version": "6.23.0",
91− "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz",
92− "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=",
37+ "ansi-styles": {
38+ "version": "3.2.1",
39+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
40+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
9341 "dev": true,
9442 "requires": {
95− "babel-runtime": "^6.22.0",
96− "core-js": "^2.4.0",
97− "regenerator-runtime": "^0.10.0"
43+ "color-convert": "^1.9.0"
9844 }
9945 },
100− "babel-runtime": {
101− "version": "6.26.0",
102− "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
103− "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
46+ "anymatch": {
47+ "version": "3.1.1",
48+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
49+ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
10450 "dev": true,
10551 "requires": {
106− "core-js": "^2.4.0",
107− "regenerator-runtime": "^0.11.0"
108− },
109− "dependencies": {
110− "regenerator-runtime": {
111− "version": "0.11.1",
112− "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
113− "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
114− "dev": true
115− }
52+ "normalize-path": "^3.0.0",
53+ "picomatch": "^2.0.4"
11654 }
11755 },
118− "base": {
119− "version": "0.11.2",
120− "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
121− "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
122− "dev": true,
123− "requires": {
124− "cache-base": "^1.0.1",
125− "class-utils": "^0.3.5",
126− "component-emitter": "^1.2.1",
127− "define-property": "^1.0.0",
128− "isobject": "^3.0.1",
129− "mixin-deep": "^1.2.0",
130− "pascalcase": "^0.1.1"
131− },
132− "dependencies": {
133− "define-property": {
134− "version": "1.0.0",
135− "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
136− "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
137− "dev": true,
138− "requires": {
139− "is-descriptor": "^1.0.0"
140− }
141− },
142− "is-accessor-descriptor": {
143− "version": "1.0.0",
144− "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
145− "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
146− "dev": true,
147− "requires": {
148− "kind-of": "^6.0.0"
149− }
150− },
151− "is-data-descriptor": {
152− "version": "1.0.0",
153− "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
154− "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
155− "dev": true,
156− "requires": {
157− "kind-of": "^6.0.0"
158− }
159− },
160− "is-descriptor": {
161− "version": "1.0.2",
162− "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
163− "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
164− "dev": true,
165− "requires": {
166− "is-accessor-descriptor": "^1.0.0",
167− "is-data-descriptor": "^1.0.0",
168− "kind-of": "^6.0.2"
169− }
170− },
171− "isobject": {
172− "version": "3.0.1",
173− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
174− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
175− "dev": true
176− },
177− "kind-of": {
178− "version": "6.0.2",
179− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
180− "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
181− "dev": true
182− }
183− }
56+ "async-limiter": {
57+ "version": "1.0.1",
58+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
59+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
60+ "dev": true
18461 },
18562 "binary-extensions": {
186− "version": "1.13.1",
187− "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
188− "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
63+ "version": "2.1.0",
64+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
65+ "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
18966 "dev": true
19067 },
19168 "boxen": {
192− "version": "1.3.0",
193− "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
194− "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
69+ "version": "3.2.0",
70+ "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz",
71+ "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==",
19572 "dev": true,
19673 "requires": {
197− "ansi-align": "^2.0.0",
198− "camelcase": "^4.0.0",
199− "chalk": "^2.0.1",
200− "cli-boxes": "^1.0.0",
201− "string-width": "^2.0.0",
74+ "ansi-align": "^3.0.0",
75+ "camelcase": "^5.3.1",
76+ "chalk": "^2.4.2",
77+ "cli-boxes": "^2.2.0",
78+ "string-width": "^3.0.0",
20279 "term-size": "^1.2.0",
80+ "type-fest": "^0.3.0",
20381 "widest-line": "^2.0.0"
204− },
205− "dependencies": {
206− "ansi-styles": {
207− "version": "3.2.1",
208− "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
209− "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
210− "dev": true,
211− "requires": {
212− "color-convert": "^1.9.0"
213− }
214− },
215− "chalk": {
216− "version": "2.4.2",
217− "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
218− "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
219− "dev": true,
220− "requires": {
221− "ansi-styles": "^3.2.1",
222− "escape-string-regexp": "^1.0.5",
223− "supports-color": "^5.3.0"
224− }
225− },
226− "supports-color": {
227− "version": "5.5.0",
228− "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
229− "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
230− "dev": true,
231− "requires": {
232− "has-flag": "^3.0.0"
233− }
234− }
23582 }
23683 },
23784 "braces": {
238− "version": "1.8.5",
239− "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
240− "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
85+ "version": "3.0.2",
86+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
87+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
24188 "dev": true,
24289 "requires": {
243− "expand-range": "^1.8.1",
244− "preserve": "^0.2.0",
245− "repeat-element": "^1.1.2"
90+ "fill-range": "^7.0.1"
24691 }
24792 },
248− "cache-base": {
249− "version": "1.0.1",
250− "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
251− "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
252− "dev": true,
253− "requires": {
254− "collection-visit": "^1.0.0",
255− "component-emitter": "^1.2.1",
256− "get-value": "^2.0.6",
257− "has-value": "^1.0.0",
258− "isobject": "^3.0.1",
259− "set-value": "^2.0.0",
260− "to-object-path": "^0.3.0",
261− "union-value": "^1.0.0",
262− "unset-value": "^1.0.0"
93+ "cacheable-request": {
94+ "version": "6.1.0",
95+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
96+ "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==",
97+ "dev": true,
98+ "requires": {
99+ "clone-response": "^1.0.2",
100+ "get-stream": "^5.1.0",
101+ "http-cache-semantics": "^4.0.0",
102+ "keyv": "^3.0.0",
103+ "lowercase-keys": "^2.0.0",
104+ "normalize-url": "^4.1.0",
105+ "responselike": "^1.0.2"
263106 },
264107 "dependencies": {
265− "isobject": {
266− "version": "3.0.1",
267− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
268− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
108+ "get-stream": {
109+ "version": "5.1.0",
110+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
111+ "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
112+ "dev": true,
113+ "requires": {
114+ "pump": "^3.0.0"
115+ }
116+ },
117+ "lowercase-keys": {
118+ "version": "2.0.0",
119+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
120+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
269121 "dev": true
270122 }
271123 }
272124 },
273125 "camelcase": {
274− "version": "4.1.0",
275− "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
276− "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
277− "dev": true
278− },
279− "capture-stack-trace": {
280− "version": "1.0.1",
281− "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz",
282− "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==",
126+ "version": "5.3.1",
127+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
128+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
283129 "dev": true
284130 },
285131 "chalk": {
286− "version": "1.1.3",
287− "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
288− "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
132+ "version": "2.4.2",
133+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
134+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
289135 "dev": true,
290136 "requires": {
291− "ansi-styles": "^2.2.1",
292− "escape-string-regexp": "^1.0.2",
293− "has-ansi": "^2.0.0",
294− "strip-ansi": "^3.0.0",
295− "supports-color": "^2.0.0"
137+ "ansi-styles": "^3.2.1",
138+ "escape-string-regexp": "^1.0.5",
139+ "supports-color": "^5.3.0"
296140 }
297141 },
298− "chardet": {
299− "version": "0.4.2",
300− "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
301− "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
302− "dev": true
303− },
304142 "chokidar": {
305− "version": "1.7.0",
306− "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
307− "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
143+ "version": "3.4.2",
144+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz",
145+ "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==",
308146 "dev": true,
309147 "requires": {
310− "anymatch": "^1.3.0",
311− "async-each": "^1.0.0",
312− "fsevents": "^1.0.0",
313− "glob-parent": "^2.0.0",
314− "inherits": "^2.0.1",
315− "is-binary-path": "^1.0.0",
316− "is-glob": "^2.0.0",
317− "path-is-absolute": "^1.0.0",
318− "readdirp": "^2.0.0"
148+ "anymatch": "~3.1.1",
149+ "braces": "~3.0.2",
150+ "fsevents": "~2.1.2",
151+ "glob-parent": "~5.1.0",
152+ "is-binary-path": "~2.1.0",
153+ "is-glob": "~4.0.1",
154+ "normalize-path": "~3.0.0",
155+ "readdirp": "~3.4.0"
319156 }
320157 },
321158 "ci-info": {
322− "version": "1.6.0",
323− "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
324− "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
159+ "version": "2.0.0",
160+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
161+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
325162 "dev": true
326163 },
327− "class-utils": {
328− "version": "0.3.6",
329− "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
330− "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
331− "dev": true,
332− "requires": {
333− "arr-union": "^3.1.0",
334− "define-property": "^0.2.5",
335− "isobject": "^3.0.0",
336− "static-extend": "^0.1.1"
337− },
338− "dependencies": {
339− "define-property": {
340− "version": "0.2.5",
341− "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
342− "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
343− "dev": true,
344− "requires": {
345− "is-descriptor": "^0.1.0"
346− }
347− },
348− "isobject": {
349− "version": "3.0.1",
350− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
351− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
352− "dev": true
353− }
354− }
355− },
356164 "cli-boxes": {
357− "version": "1.0.0",
358− "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
359− "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=",
360− "dev": true
361− },
362− "cli-cursor": {
363− "version": "2.1.0",
364− "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
365− "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
366− "dev": true,
367− "requires": {
368− "restore-cursor": "^2.0.0"
369− }
370− },
371− "cli-width": {
372165 "version": "2.2.0",
373− "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
374− "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
166+ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz",
167+ "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==",
375168 "dev": true
376169 },
377170 "clipboard": {
378− "version": "2.0.4",
379− "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz",
380− "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==",
171+ "version": "2.0.6",
172+ "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
173+ "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
381174 "dev": true,
382175 "optional": true,
383176 "requires": {
@@ -387,52 +180,23 @@
387180 }
388181 },
389182 "cliui": {
390− "version": "3.2.0",
391− "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
392− "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
183+ "version": "5.0.0",
184+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
185+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
393186 "dev": true,
394187 "requires": {
395− "string-width": "^1.0.1",
396− "strip-ansi": "^3.0.1",
397− "wrap-ansi": "^2.0.0"
398− },
399− "dependencies": {
400− "is-fullwidth-code-point": {
401− "version": "1.0.0",
402− "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
403− "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
404− "dev": true,
405− "requires": {
406− "number-is-nan": "^1.0.0"
407− }
408− },
409− "string-width": {
410− "version": "1.0.2",
411− "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
412− "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
413− "dev": true,
414− "requires": {
415− "code-point-at": "^1.0.0",
416− "is-fullwidth-code-point": "^1.0.0",
417− "strip-ansi": "^3.0.0"
418− }
419− }
188+ "string-width": "^3.1.0",
189+ "strip-ansi": "^5.2.0",
190+ "wrap-ansi": "^5.1.0"
420191 }
421192 },
422− "code-point-at": {
423− "version": "1.1.0",
424− "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
425− "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
426− "dev": true
427− },
428− "collection-visit": {
429− "version": "1.0.0",
430− "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
431− "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
193+ "clone-response": {
194+ "version": "1.0.2",
195+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
196+ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
432197 "dev": true,
433198 "requires": {
434− "map-visit": "^1.0.0",
435− "object-visit": "^1.0.0"
199+ "mimic-response": "^1.0.0"
436200 }
437201 },
438202 "color-convert": {
@@ -450,16 +214,10 @@
450214 "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
451215 "dev": true
452216 },
453− "component-emitter": {
454− "version": "1.3.0",
455− "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
456− "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
457− "dev": true
458− },
459217 "configstore": {
460− "version": "3.1.2",
461− "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz",
462− "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==",
218+ "version": "4.0.0",
219+ "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz",
220+ "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==",
463221 "dev": true,
464222 "requires": {
465223 "dot-prop": "^4.1.0",
@@ -468,6 +226,17 @@
468226 "unique-string": "^1.0.0",
469227 "write-file-atomic": "^2.0.0",
470228 "xdg-basedir": "^3.0.0"
229+ },
230+ "dependencies": {
231+ "make-dir": {
232+ "version": "1.3.0",
233+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
234+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
235+ "dev": true,
236+ "requires": {
237+ "pify": "^3.0.0"
238+ }
239+ }
471240 }
472241 },
473242 "connect": {
@@ -488,44 +257,16 @@
488257 "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==",
489258 "dev": true
490259 },
491− "copy-descriptor": {
492− "version": "0.1.1",
493− "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
494− "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
495− "dev": true
496− },
497− "core-js": {
498− "version": "2.6.10",
499− "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz",
500− "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==",
501− "dev": true
502− },
503− "core-util-is": {
504− "version": "1.0.2",
505− "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
506− "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
507− "dev": true
508− },
509260 "cp-file": {
510− "version": "4.2.0",
511− "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-4.2.0.tgz",
512− "integrity": "sha1-cVNhZjtx7eC23dvDyA4roC5yXsM=",
261+ "version": "7.0.0",
262+ "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz",
263+ "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==",
513264 "dev": true,
514265 "requires": {
515266 "graceful-fs": "^4.1.2",
516− "make-dir": "^1.0.0",
267+ "make-dir": "^3.0.0",
517268 "nested-error-stacks": "^2.0.0",
518− "pify": "^2.3.0",
519− "safe-buffer": "^5.0.1"
520− }
521− },
522− "create-error-class": {
523− "version": "3.0.2",
524− "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
525− "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
526− "dev": true,
527− "requires": {
528− "capture-stack-trace": "^1.0.0"
269+ "p-event": "^4.1.0"
529270 }
530271 },
531272 "cross-spawn": {
@@ -537,6 +278,24 @@
537278 "lru-cache": "^4.0.1",
538279 "shebang-command": "^1.2.0",
539280 "which": "^1.2.9"
281+ },
282+ "dependencies": {
283+ "lru-cache": {
284+ "version": "4.1.5",
285+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
286+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
287+ "dev": true,
288+ "requires": {
289+ "pseudomap": "^1.0.2",
290+ "yallist": "^2.1.2"
291+ }
292+ },
293+ "yallist": {
294+ "version": "2.1.2",
295+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
296+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
297+ "dev": true
298+ }
540299 }
541300 },
542301 "crypto-random-string": {
@@ -560,11 +319,14 @@
560319 "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
561320 "dev": true
562321 },
563− "decode-uri-component": {
564− "version": "0.2.0",
565− "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
566− "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
567− "dev": true
322+ "decompress-response": {
323+ "version": "3.3.0",
324+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
325+ "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
326+ "dev": true,
327+ "requires": {
328+ "mimic-response": "^1.0.0"
329+ }
568330 },
569331 "deep-extend": {
570332 "version": "0.6.0",
@@ -572,58 +334,11 @@
572334 "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
573335 "dev": true
574336 },
575− "define-property": {
576− "version": "2.0.2",
577− "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
578− "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
579− "dev": true,
580− "requires": {
581− "is-descriptor": "^1.0.2",
582− "isobject": "^3.0.1"
583− },
584− "dependencies": {
585− "is-accessor-descriptor": {
586− "version": "1.0.0",
587− "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
588− "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
589− "dev": true,
590− "requires": {
591− "kind-of": "^6.0.0"
592− }
593− },
594− "is-data-descriptor": {
595− "version": "1.0.0",
596− "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
597− "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
598− "dev": true,
599− "requires": {
600− "kind-of": "^6.0.0"
601− }
602− },
603− "is-descriptor": {
604− "version": "1.0.2",
605− "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
606− "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
607− "dev": true,
608− "requires": {
609− "is-accessor-descriptor": "^1.0.0",
610− "is-data-descriptor": "^1.0.0",
611− "kind-of": "^6.0.2"
612− }
613− },
614− "isobject": {
615− "version": "3.0.1",
616− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
617− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
618− "dev": true
619− },
620− "kind-of": {
621− "version": "6.0.2",
622− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
623− "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
624− "dev": true
625− }
626− }
337+ "defer-to-connect": {
338+ "version": "1.1.3",
339+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
340+ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==",
341+ "dev": true
627342 },
628343 "delegate": {
629344 "version": "3.2.0",
@@ -645,66 +360,80 @@
645360 "dev": true
646361 },
647362 "docsify": {
648− "version": "4.9.4",
649− "resolved": "https://registry.npmjs.org/docsify/-/docsify-4.9.4.tgz",
650− "integrity": "sha512-Xtm6sfrNU7cqOViWMewDhscn0cySF60q2KTKok9OaPmzt6nRkTAIvYU4dj916IT21o/b336Or3vO2hsvmaQzxg==",
363+ "version": "4.11.4",
364+ "resolved": "https://registry.npmjs.org/docsify/-/docsify-4.11.4.tgz",
365+ "integrity": "sha512-Qwt98y6ddM2Wb46gRH/zQpEAvw70AlIpzVlB9Wi2u2T2REg9O+bXMpJ27F5TaRTn2bD6SF1VyZYNUfimpihZwQ==",
651366 "dev": true,
652367 "requires": {
653− "marked": "^0.5.1",
654− "medium-zoom": "^0.4.0",
655− "opencollective": "^1.0.3",
656− "prismjs": "^1.15.0",
368+ "dompurify": "^2.0.8",
369+ "marked": "^0.7.0",
370+ "medium-zoom": "^1.0.5",
371+ "opencollective-postinstall": "^2.0.2",
372+ "prismjs": "^1.19.0",
373+ "strip-indent": "^3.0.0",
657374 "tinydate": "^1.0.0",
658375 "tweezer.js": "^1.4.0"
659376 }
660377 },
661378 "docsify-cli": {
662− "version": "4.3.0",
663− "resolved": "https://registry.npmjs.org/docsify-cli/-/docsify-cli-4.3.0.tgz",
664− "integrity": "sha512-88O1sMeoZv4lb5GPSJzDtOAv2KzBjpQaSqVlVqY+6hGJfb2wpz9PvlUhvlgPq54zu4kPDeCCyUYgqa/llhKg3w==",
379+ "version": "4.4.1",
380+ "resolved": "https://registry.npmjs.org/docsify-cli/-/docsify-cli-4.4.1.tgz",
381+ "integrity": "sha512-M5VU/8UCILz87D519KnURH3LA+A3RAAqj7ifDv4xOUf4c32QDkWSETS3yLmXlTNdxhATVi5P1fVklnvVW4uOyw==",
665382 "dev": true,
666383 "requires": {
667− "chalk": "^1.1.3",
384+ "chalk": "^2.4.2",
668385 "connect": "^3.6.0",
669386 "connect-livereload": "^0.6.0",
670− "cp-file": "^4.1.1",
671− "docsify": ">=3",
387+ "cp-file": "^7.0.0",
388+ "docsify": "^4.10.2",
672389 "docsify-server-renderer": ">=4",
673− "fs-extra": "^2.1.2",
674− "livereload": "^0.7.0",
675− "lru-cache": "^4.1.1",
676− "opn": "^5.3.0",
390+ "fs-extra": "^8.1.0",
391+ "get-port": "^5.0.0",
392+ "livereload": "^0.9.1",
393+ "lru-cache": "^5.1.1",
394+ "open": "^6.4.0",
677395 "serve-static": "^1.12.1",
678− "update-notifier": "^2.1.0",
679− "y18n": "^3.2.1",
396+ "update-notifier": "^3.0.1",
680397 "yargonaut": "^1.1.2",
681− "yargs": "^7.0.2"
398+ "yargs": "^14.2.0"
682399 }
683400 },
684401 "docsify-server-renderer": {
685− "version": "4.9.1",
686− "resolved": "https://registry.npmjs.org/docsify-server-renderer/-/docsify-server-renderer-4.9.1.tgz",
687− "integrity": "sha512-JERMD3yEJq38nSim/o1VGBoyqxsRo1VRscafpkx3mT7g07orOg5UARUgztKQNmv+0xnkWsmu+BMr9nsurXmBMQ==",
402+ "version": "4.11.4",
403+ "resolved": "https://registry.npmjs.org/docsify-server-renderer/-/docsify-server-renderer-4.11.4.tgz",
404+ "integrity": "sha512-TxOxqX/fwBFLHz788PtB0OeVis1EDWCVK8CEE/fvxTzQqsgZNTw2UO1wEg1qt/uuldJps3G+DPv/FN9xIeQgcg==",
688405 "dev": true,
689406 "requires": {
690− "debug": "^2.6.8",
691− "docsify": "^4.8.0",
692− "node-fetch": "^1.7.0",
693− "resolve-pathname": "^2.1.0"
407+ "debug": "^4.1.1",
408+ "docsify": "^4.11.2",
409+ "dompurify": "^2.0.8",
410+ "node-fetch": "^2.6.0",
411+ "resolve-pathname": "^3.0.0"
694412 },
695413 "dependencies": {
696− "node-fetch": {
697− "version": "1.7.3",
698− "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
699− "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
414+ "debug": {
415+ "version": "4.1.1",
416+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
417+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
700418 "dev": true,
701419 "requires": {
702− "encoding": "^0.1.11",
703− "is-stream": "^1.0.1"
420+ "ms": "^2.1.1"
704421 }
422+ },
423+ "ms": {
424+ "version": "2.1.2",
425+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
426+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
427+ "dev": true
705428 }
706429 }
707430 },
431+ "dompurify": {
432+ "version": "2.0.12",
433+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.0.12.tgz",
434+ "integrity": "sha512-Fl8KseK1imyhErHypFPA8qpq9gPzlsJ/EukA6yk9o0gX23p1TzC+rh9LqNg1qvErRTc0UNMYlKxEGSfSh43NDg==",
435+ "dev": true
436+ },
708437 "dot-prop": {
709438 "version": "4.2.0",
710439 "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
@@ -726,28 +455,25 @@
726455 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
727456 "dev": true
728457 },
458+ "emoji-regex": {
459+ "version": "7.0.3",
460+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
461+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
462+ "dev": true
463+ },
729464 "encodeurl": {
730465 "version": "1.0.2",
731466 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
732467 "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
733468 "dev": true
734469 },
735− "encoding": {
736− "version": "0.1.12",
737− "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
738− "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
739− "dev": true,
740− "requires": {
741− "iconv-lite": "~0.4.13"
742− }
743− },
744− "error-ex": {
745− "version": "1.3.2",
746− "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
747− "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
470+ "end-of-stream": {
471+ "version": "1.4.4",
472+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
473+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
748474 "dev": true,
749475 "requires": {
750− "is-arrayish": "^0.2.1"
476+ "once": "^1.4.0"
751477 }
752478 },
753479 "escape-html": {
@@ -783,146 +509,43 @@
783509 "strip-eof": "^1.0.0"
784510 }
785511 },
786− "expand-brackets": {
787− "version": "0.1.5",
788− "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
789− "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
512+ "figlet": {
513+ "version": "1.5.0",
514+ "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.0.tgz",
515+ "integrity": "sha512-ZQJM4aifMpz6H19AW1VqvZ7l4pOE9p7i/3LyxgO2kp+PO/VcDYNqIHEMtkccqIhTXMKci4kjueJr/iCQEaT/Ww==",
516+ "dev": true
517+ },
518+ "fill-range": {
519+ "version": "7.0.1",
520+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
521+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
790522 "dev": true,
791523 "requires": {
792− "is-posix-bracket": "^0.1.0"
524+ "to-regex-range": "^5.0.1"
793525 }
794526 },
795− "expand-range": {
796− "version": "1.8.2",
797− "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
798− "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
527+ "finalhandler": {
528+ "version": "1.1.2",
529+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
530+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
799531 "dev": true,
800532 "requires": {
801− "fill-range": "^2.1.0"
533+ "debug": "2.6.9",
534+ "encodeurl": "~1.0.2",
535+ "escape-html": "~1.0.3",
536+ "on-finished": "~2.3.0",
537+ "parseurl": "~1.3.3",
538+ "statuses": "~1.5.0",
539+ "unpipe": "~1.0.0"
802540 }
803541 },
804− "extend-shallow": {
805− "version": "3.0.2",
806− "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
807− "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
542+ "find-up": {
543+ "version": "3.0.0",
544+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
545+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
808546 "dev": true,
809547 "requires": {
810− "assign-symbols": "^1.0.0",
811− "is-extendable": "^1.0.1"
812− },
813− "dependencies": {
814− "is-extendable": {
815− "version": "1.0.1",
816− "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
817− "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
818− "dev": true,
819− "requires": {
820− "is-plain-object": "^2.0.4"
821− }
822− }
823− }
824− },
825− "external-editor": {
826− "version": "2.2.0",
827− "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
828− "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
829− "dev": true,
830− "requires": {
831− "chardet": "^0.4.0",
832− "iconv-lite": "^0.4.17",
833− "tmp": "^0.0.33"
834− }
835− },
836− "extglob": {
837− "version": "0.3.2",
838− "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
839− "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
840− "dev": true,
841− "requires": {
842− "is-extglob": "^1.0.0"
843− }
844− },
845− "figlet": {
846− "version": "1.2.4",
847− "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.2.4.tgz",
848− "integrity": "sha512-mv8YA9RruB4C5QawPaD29rEVx3N97ZTyNrE4DAfbhuo6tpcMdKnPVo8MlyT3RP5uPcg5M14bEJBq7kjFf4kAWg==",
849− "dev": true
850− },
851− "figures": {
852− "version": "2.0.0",
853− "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
854− "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
855− "dev": true,
856− "requires": {
857− "escape-string-regexp": "^1.0.5"
858− }
859− },
860− "filename-regex": {
861− "version": "2.0.1",
862− "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
863− "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
864− "dev": true
865− },
866− "fill-range": {
867− "version": "2.2.4",
868− "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
869− "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
870− "dev": true,
871− "requires": {
872− "is-number": "^2.1.0",
873− "isobject": "^2.0.0",
874− "randomatic": "^3.0.0",
875− "repeat-element": "^1.1.2",
876− "repeat-string": "^1.5.2"
877− }
878− },
879− "finalhandler": {
880− "version": "1.1.2",
881− "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
882− "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
883− "dev": true,
884− "requires": {
885− "debug": "2.6.9",
886− "encodeurl": "~1.0.2",
887− "escape-html": "~1.0.3",
888− "on-finished": "~2.3.0",
889− "parseurl": "~1.3.3",
890− "statuses": "~1.5.0",
891− "unpipe": "~1.0.0"
892− }
893− },
894− "find-up": {
895− "version": "1.1.2",
896− "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
897− "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
898− "dev": true,
899− "requires": {
900− "path-exists": "^2.0.0",
901− "pinkie-promise": "^2.0.0"
902− }
903− },
904− "for-in": {
905− "version": "1.0.2",
906− "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
907− "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
908− "dev": true
909− },
910− "for-own": {
911− "version": "0.1.5",
912− "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
913− "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
914− "dev": true,
915− "requires": {
916− "for-in": "^1.0.1"
917− }
918− },
919− "fragment-cache": {
920− "version": "0.2.1",
921− "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
922− "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
923− "dev": true,
924− "requires": {
925− "map-cache": "^0.2.2"
548+ "locate-path": "^3.0.0"
926549 }
927550 },
928551 "fresh": {
@@ -932,598 +555,48 @@
932555 "dev": true
933556 },
934557 "fs-extra": {
935− "version": "2.1.2",
936− "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz",
937− "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=",
558+ "version": "8.1.0",
559+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
560+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
938561 "dev": true,
939562 "requires": {
940− "graceful-fs": "^4.1.2",
941− "jsonfile": "^2.1.0"
563+ "graceful-fs": "^4.2.0",
564+ "jsonfile": "^4.0.0",
565+ "universalify": "^0.1.0"
942566 }
943567 },
944568 "fsevents": {
945− "version": "1.2.9",
946− "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
947− "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
569+ "version": "2.1.3",
570+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
571+ "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
948572 "dev": true,
949− "optional": true,
950− "requires": {
951− "nan": "^2.12.1",
952− "node-pre-gyp": "^0.12.0"
953− },
954− "dependencies": {
955− "abbrev": {
956− "version": "1.1.1",
957− "bundled": true,
958− "dev": true,
959− "optional": true
960− },
961− "ansi-regex": {
962− "version": "2.1.1",
963− "bundled": true,
964− "dev": true,
965− "optional": true
966− },
967− "aproba": {
968− "version": "1.2.0",
969− "bundled": true,
970− "dev": true,
971− "optional": true
972− },
973− "are-we-there-yet": {
974− "version": "1.1.5",
975− "bundled": true,
976− "dev": true,
977− "optional": true,
978− "requires": {
979− "delegates": "^1.0.0",
980− "readable-stream": "^2.0.6"
981− }
982− },
983− "balanced-match": {
984− "version": "1.0.0",
985− "bundled": true,
986− "dev": true,
987− "optional": true
988− },
989− "brace-expansion": {
990− "version": "1.1.11",
991− "bundled": true,
992− "dev": true,
993− "optional": true,
994− "requires": {
995− "balanced-match": "^1.0.0",
996− "concat-map": "0.0.1"
997− }
998− },
999− "chownr": {
1000− "version": "1.1.1",
1001− "bundled": true,
1002− "dev": true,
1003− "optional": true
1004− },
1005− "code-point-at": {
1006− "version": "1.1.0",
1007− "bundled": true,
1008− "dev": true,
1009− "optional": true
1010− },
1011− "concat-map": {
1012− "version": "0.0.1",
1013− "bundled": true,
1014− "dev": true,
1015− "optional": true
1016− },
1017− "console-control-strings": {
1018− "version": "1.1.0",
1019− "bundled": true,
1020− "dev": true,
1021− "optional": true
1022− },
1023− "core-util-is": {
1024− "version": "1.0.2",
1025− "bundled": true,
1026− "dev": true,
1027− "optional": true
1028− },
1029− "debug": {
1030− "version": "4.1.1",
1031− "bundled": true,
1032− "dev": true,
1033− "optional": true,
1034− "requires": {
1035− "ms": "^2.1.1"
1036− }
1037− },
1038− "deep-extend": {
1039− "version": "0.6.0",
1040− "bundled": true,
1041− "dev": true,
1042− "optional": true
1043− },
1044− "delegates": {
1045− "version": "1.0.0",
1046− "bundled": true,
1047− "dev": true,
1048− "optional": true
1049− },
1050− "detect-libc": {
1051− "version": "1.0.3",
1052− "bundled": true,
1053− "dev": true,
1054− "optional": true
1055− },
1056− "fs-minipass": {
1057− "version": "1.2.5",
1058− "bundled": true,
1059− "dev": true,
1060− "optional": true,
1061− "requires": {
1062− "minipass": "^2.2.1"
1063− }
1064− },
1065− "fs.realpath": {
1066− "version": "1.0.0",
1067− "bundled": true,
1068− "dev": true,
1069− "optional": true
1070− },
1071− "gauge": {
1072− "version": "2.7.4",
1073− "bundled": true,
1074− "dev": true,
1075− "optional": true,
1076− "requires": {
1077− "aproba": "^1.0.3",
1078− "console-control-strings": "^1.0.0",
1079− "has-unicode": "^2.0.0",
1080− "object-assign": "^4.1.0",
1081− "signal-exit": "^3.0.0",
1082− "string-width": "^1.0.1",
1083− "strip-ansi": "^3.0.1",
1084− "wide-align": "^1.1.0"
1085− }
1086− },
1087− "glob": {
1088− "version": "7.1.3",
1089− "bundled": true,
1090− "dev": true,
1091− "optional": true,
1092− "requires": {
1093− "fs.realpath": "^1.0.0",
1094− "inflight": "^1.0.4",
1095− "inherits": "2",
1096− "minimatch": "^3.0.4",
1097− "once": "^1.3.0",
1098− "path-is-absolute": "^1.0.0"
1099− }
1100− },
1101− "has-unicode": {
1102− "version": "2.0.1",
1103− "bundled": true,
1104− "dev": true,
1105− "optional": true
1106− },
1107− "iconv-lite": {
1108− "version": "0.4.24",
1109− "bundled": true,
1110− "dev": true,
1111− "optional": true,
1112− "requires": {
1113− "safer-buffer": ">= 2.1.2 < 3"
1114− }
1115− },
1116− "ignore-walk": {
1117− "version": "3.0.1",
1118− "bundled": true,
1119− "dev": true,
1120− "optional": true,
1121− "requires": {
1122− "minimatch": "^3.0.4"
1123− }
1124− },
1125− "inflight": {
1126− "version": "1.0.6",
1127− "bundled": true,
1128− "dev": true,
1129− "optional": true,
1130− "requires": {
1131− "once": "^1.3.0",
1132− "wrappy": "1"
1133− }
1134− },
1135− "inherits": {
1136− "version": "2.0.3",
1137− "bundled": true,
1138− "dev": true,
1139− "optional": true
1140− },
1141− "ini": {
1142− "version": "1.3.5",
1143− "bundled": true,
1144− "dev": true,
1145− "optional": true
1146− },
1147− "is-fullwidth-code-point": {
1148− "version": "1.0.0",
1149− "bundled": true,
1150− "dev": true,
1151− "optional": true,
1152− "requires": {
1153− "number-is-nan": "^1.0.0"
1154− }
1155− },
1156− "isarray": {
1157− "version": "1.0.0",
1158− "bundled": true,
1159− "dev": true,
1160− "optional": true
1161− },
1162− "minimatch": {
1163− "version": "3.0.4",
1164− "bundled": true,
1165− "dev": true,
1166− "optional": true,
1167− "requires": {
1168− "brace-expansion": "^1.1.7"
1169− }
1170− },
1171− "minimist": {
1172− "version": "0.0.8",
1173− "bundled": true,
1174− "dev": true,
1175− "optional": true
1176− },
1177− "minipass": {
1178− "version": "2.3.5",
1179− "bundled": true,
1180− "dev": true,
1181− "optional": true,
1182− "requires": {
1183− "safe-buffer": "^5.1.2",
1184− "yallist": "^3.0.0"
1185− }
1186− },
1187− "minizlib": {
1188− "version": "1.2.1",
1189− "bundled": true,
1190− "dev": true,
1191− "optional": true,
1192− "requires": {
1193− "minipass": "^2.2.1"
1194− }
1195− },
1196− "mkdirp": {
1197− "version": "0.5.1",
1198− "bundled": true,
1199− "dev": true,
1200− "optional": true,
1201− "requires": {
1202− "minimist": "0.0.8"
1203− }
1204− },
1205− "ms": {
1206− "version": "2.1.1",
1207− "bundled": true,
1208− "dev": true,
1209− "optional": true
1210− },
1211− "needle": {
1212− "version": "2.3.0",
1213− "bundled": true,
1214− "dev": true,
1215− "optional": true,
1216− "requires": {
1217− "debug": "^4.1.0",
1218− "iconv-lite": "^0.4.4",
1219− "sax": "^1.2.4"
1220− }
1221− },
1222− "node-pre-gyp": {
1223− "version": "0.12.0",
1224− "bundled": true,
1225− "dev": true,
1226− "optional": true,
1227− "requires": {
1228− "detect-libc": "^1.0.2",
1229− "mkdirp": "^0.5.1",
1230− "needle": "^2.2.1",
1231− "nopt": "^4.0.1",
1232− "npm-packlist": "^1.1.6",
1233− "npmlog": "^4.0.2",
1234− "rc": "^1.2.7",
1235− "rimraf": "^2.6.1",
1236− "semver": "^5.3.0",
1237− "tar": "^4"
1238− }
1239− },
1240− "nopt": {
1241− "version": "4.0.1",
1242− "bundled": true,
1243− "dev": true,
1244− "optional": true,
1245− "requires": {
1246− "abbrev": "1",
1247− "osenv": "^0.1.4"
1248− }
1249− },
1250− "npm-bundled": {
1251− "version": "1.0.6",
1252− "bundled": true,
1253− "dev": true,
1254− "optional": true
1255− },
1256− "npm-packlist": {
1257− "version": "1.4.1",
1258− "bundled": true,
1259− "dev": true,
1260− "optional": true,
1261− "requires": {
1262− "ignore-walk": "^3.0.1",
1263− "npm-bundled": "^1.0.1"
1264− }
1265− },
1266− "npmlog": {
1267− "version": "4.1.2",
1268− "bundled": true,
1269− "dev": true,
1270− "optional": true,
1271− "requires": {
1272− "are-we-there-yet": "~1.1.2",
1273− "console-control-strings": "~1.1.0",
1274− "gauge": "~2.7.3",
1275− "set-blocking": "~2.0.0"
1276− }
1277− },
1278− "number-is-nan": {
1279− "version": "1.0.1",
1280− "bundled": true,
1281− "dev": true,
1282− "optional": true
1283− },
1284− "object-assign": {
1285− "version": "4.1.1",
1286− "bundled": true,
1287− "dev": true,
1288− "optional": true
1289− },
1290− "once": {
1291− "version": "1.4.0",
1292− "bundled": true,
1293− "dev": true,
1294− "optional": true,
1295− "requires": {
1296− "wrappy": "1"
1297− }
1298− },
1299− "os-homedir": {
1300− "version": "1.0.2",
1301− "bundled": true,
1302− "dev": true,
1303− "optional": true
1304− },
1305− "os-tmpdir": {
1306− "version": "1.0.2",
1307− "bundled": true,
1308− "dev": true,
1309− "optional": true
1310− },
1311− "osenv": {
1312− "version": "0.1.5",
1313− "bundled": true,
1314− "dev": true,
1315− "optional": true,
1316− "requires": {
1317− "os-homedir": "^1.0.0",
1318− "os-tmpdir": "^1.0.0"
1319− }
1320− },
1321− "path-is-absolute": {
1322− "version": "1.0.1",
1323− "bundled": true,
1324− "dev": true,
1325− "optional": true
1326− },
1327− "process-nextick-args": {
1328− "version": "2.0.0",
1329− "bundled": true,
1330− "dev": true,
1331− "optional": true
1332− },
1333− "rc": {
1334− "version": "1.2.8",
1335− "bundled": true,
1336− "dev": true,
1337− "optional": true,
1338− "requires": {
1339− "deep-extend": "^0.6.0",
1340− "ini": "~1.3.0",
1341− "minimist": "^1.2.0",
1342− "strip-json-comments": "~2.0.1"
1343− },
1344− "dependencies": {
1345− "minimist": {
1346− "version": "1.2.0",
1347− "bundled": true,
1348− "dev": true,
1349− "optional": true
1350− }
1351− }
1352− },
1353− "readable-stream": {
1354− "version": "2.3.6",
1355− "bundled": true,
1356− "dev": true,
1357− "optional": true,
1358− "requires": {
1359− "core-util-is": "~1.0.0",
1360− "inherits": "~2.0.3",
1361− "isarray": "~1.0.0",
1362− "process-nextick-args": "~2.0.0",
1363− "safe-buffer": "~5.1.1",
1364− "string_decoder": "~1.1.1",
1365− "util-deprecate": "~1.0.1"
1366− }
1367− },
1368− "rimraf": {
1369− "version": "2.6.3",
1370− "bundled": true,
1371− "dev": true,
1372− "optional": true,
1373− "requires": {
1374− "glob": "^7.1.3"
1375− }
1376− },
1377− "safe-buffer": {
1378− "version": "5.1.2",
1379− "bundled": true,
1380− "dev": true,
1381− "optional": true
1382− },
1383− "safer-buffer": {
1384− "version": "2.1.2",
1385− "bundled": true,
1386− "dev": true,
1387− "optional": true
1388− },
1389− "sax": {
1390− "version": "1.2.4",
1391− "bundled": true,
1392− "dev": true,
1393− "optional": true
1394− },
1395− "semver": {
1396− "version": "5.7.0",
1397− "bundled": true,
1398− "dev": true,
1399− "optional": true
1400− },
1401− "set-blocking": {
1402− "version": "2.0.0",
1403− "bundled": true,
1404− "dev": true,
1405− "optional": true
1406− },
1407− "signal-exit": {
1408− "version": "3.0.2",
1409− "bundled": true,
1410− "dev": true,
1411− "optional": true
1412− },
1413− "string-width": {
1414− "version": "1.0.2",
1415− "bundled": true,
1416− "dev": true,
1417− "optional": true,
1418− "requires": {
1419− "code-point-at": "^1.0.0",
1420− "is-fullwidth-code-point": "^1.0.0",
1421− "strip-ansi": "^3.0.0"
1422− }
1423− },
1424− "string_decoder": {
1425− "version": "1.1.1",
1426− "bundled": true,
1427− "dev": true,
1428− "optional": true,
1429− "requires": {
1430− "safe-buffer": "~5.1.0"
1431− }
1432− },
1433− "strip-ansi": {
1434− "version": "3.0.1",
1435− "bundled": true,
1436− "dev": true,
1437− "optional": true,
1438− "requires": {
1439− "ansi-regex": "^2.0.0"
1440− }
1441− },
1442− "strip-json-comments": {
1443− "version": "2.0.1",
1444− "bundled": true,
1445− "dev": true,
1446− "optional": true
1447− },
1448− "tar": {
1449− "version": "4.4.8",
1450− "bundled": true,
1451− "dev": true,
1452− "optional": true,
1453− "requires": {
1454− "chownr": "^1.1.1",
1455− "fs-minipass": "^1.2.5",
1456− "minipass": "^2.3.4",
1457− "minizlib": "^1.1.1",
1458− "mkdirp": "^0.5.0",
1459− "safe-buffer": "^5.1.2",
1460− "yallist": "^3.0.2"
1461− }
1462− },
1463− "util-deprecate": {
1464− "version": "1.0.2",
1465− "bundled": true,
1466− "dev": true,
1467− "optional": true
1468− },
1469− "wide-align": {
1470− "version": "1.1.3",
1471− "bundled": true,
1472− "dev": true,
1473− "optional": true,
1474− "requires": {
1475− "string-width": "^1.0.2 || 2"
1476− }
1477− },
1478− "wrappy": {
1479− "version": "1.0.2",
1480− "bundled": true,
1481− "dev": true,
1482− "optional": true
1483− },
1484− "yallist": {
1485− "version": "3.0.3",
1486− "bundled": true,
1487− "dev": true,
1488− "optional": true
1489− }
1490− }
573+ "optional": true
1491574 },
1492575 "get-caller-file": {
1493− "version": "1.0.3",
1494− "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
1495− "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
576+ "version": "2.0.5",
577+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
578+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
579+ "dev": true
580+ },
581+ "get-port": {
582+ "version": "5.1.1",
583+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz",
584+ "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==",
1496585 "dev": true
1497586 },
1498587 "get-stream": {
1499588 "version": "3.0.0",
1500− "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
589+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
1501590 "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
1502591 "dev": true
1503592 },
1504− "get-value": {
1505− "version": "2.0.6",
1506− "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
1507− "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
1508− "dev": true
1509− },
1510− "glob-base": {
1511− "version": "0.3.0",
1512− "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
1513− "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
1514− "dev": true,
1515− "requires": {
1516− "glob-parent": "^2.0.0",
1517− "is-glob": "^2.0.0"
1518− }
1519− },
1520593 "glob-parent": {
1521− "version": "2.0.0",
1522− "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
1523− "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
594+ "version": "5.1.1",
595+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
596+ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
1524597 "dev": true,
1525598 "requires": {
1526− "is-glob": "^2.0.0"
599+ "is-glob": "^4.0.1"
1527600 }
1528601 },
1529602 "global-dirs": {
@@ -1546,28 +619,39 @@
1546619 }
1547620 },
1548621 "got": {
1549− "version": "6.7.1",
1550− "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz",
1551− "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
622+ "version": "9.6.0",
623+ "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
624+ "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==",
1552625 "dev": true,
1553626 "requires": {
1554− "create-error-class": "^3.0.0",
627+ "@sindresorhus/is": "^0.14.0",
628+ "@szmarczak/http-timer": "^1.1.2",
629+ "cacheable-request": "^6.0.0",
630+ "decompress-response": "^3.3.0",
1555631 "duplexer3": "^0.1.4",
1556− "get-stream": "^3.0.0",
1557− "is-redirect": "^1.0.0",
1558− "is-retry-allowed": "^1.0.0",
1559− "is-stream": "^1.0.0",
1560− "lowercase-keys": "^1.0.0",
1561− "safe-buffer": "^5.0.1",
1562− "timed-out": "^4.0.0",
1563− "unzip-response": "^2.0.1",
1564− "url-parse-lax": "^1.0.0"
632+ "get-stream": "^4.1.0",
633+ "lowercase-keys": "^1.0.1",
634+ "mimic-response": "^1.0.1",
635+ "p-cancelable": "^1.0.0",
636+ "to-readable-stream": "^1.0.0",
637+ "url-parse-lax": "^3.0.0"
638+ },
639+ "dependencies": {
640+ "get-stream": {
641+ "version": "4.1.0",
642+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
643+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
644+ "dev": true,
645+ "requires": {
646+ "pump": "^3.0.0"
647+ }
648+ }
1565649 }
1566650 },
1567651 "graceful-fs": {
1568− "version": "4.2.3",
1569− "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
1570− "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
652+ "version": "4.2.4",
653+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
654+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
1571655 "dev": true
1572656 },
1573657 "has-ansi": {
@@ -1577,6 +661,14 @@
1577661 "dev": true,
1578662 "requires": {
1579663 "ansi-regex": "^2.0.0"
664+ },
665+ "dependencies": {
666+ "ansi-regex": {
667+ "version": "2.1.1",
668+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
669+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
670+ "dev": true
671+ }
1580672 }
1581673 },
1582674 "has-flag": {
@@ -1585,70 +677,16 @@
1585677 "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
1586678 "dev": true
1587679 },
1588− "has-value": {
1589− "version": "1.0.0",
1590− "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
1591− "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
1592− "dev": true,
1593− "requires": {
1594− "get-value": "^2.0.6",
1595− "has-values": "^1.0.0",
1596− "isobject": "^3.0.0"
1597− },
1598− "dependencies": {
1599− "isobject": {
1600− "version": "3.0.1",
1601− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
1602− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
1603− "dev": true
1604− }
1605− }
1606− },
1607− "has-values": {
1608− "version": "1.0.0",
1609− "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
1610− "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
1611− "dev": true,
1612− "requires": {
1613− "is-number": "^3.0.0",
1614− "kind-of": "^4.0.0"
1615− },
1616− "dependencies": {
1617− "is-number": {
1618− "version": "3.0.0",
1619− "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
1620− "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
1621− "dev": true,
1622− "requires": {
1623− "kind-of": "^3.0.2"
1624− },
1625− "dependencies": {
1626− "kind-of": {
1627− "version": "3.2.2",
1628− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1629− "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1630− "dev": true,
1631− "requires": {
1632− "is-buffer": "^1.1.5"
1633− }
1634− }
1635− }
1636− },
1637− "kind-of": {
1638− "version": "4.0.0",
1639− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
1640− "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
1641− "dev": true,
1642− "requires": {
1643− "is-buffer": "^1.1.5"
1644− }
1645− }
1646− }
680+ "has-yarn": {
681+ "version": "2.1.0",
682+ "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
683+ "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==",
684+ "dev": true
1647685 },
1648− "hosted-git-info": {
1649− "version": "2.8.5",
1650− "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
1651− "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
686+ "http-cache-semantics": {
687+ "version": "4.1.0",
688+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
689+ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
1652690 "dev": true
1653691 },
1654692 "http-errors": {
@@ -1664,15 +702,6 @@
1664702 "toidentifier": "1.0.0"
1665703 }
1666704 },
1667− "iconv-lite": {
1668− "version": "0.4.24",
1669− "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1670− "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1671− "dev": true,
1672− "requires": {
1673− "safer-buffer": ">= 2.1.2 < 3"
1674− }
1675− },
1676705 "import-lazy": {
1677706 "version": "2.1.0",
1678707 "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
@@ -1697,125 +726,28 @@
1697726 "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
1698727 "dev": true
1699728 },
1700− "inquirer": {
1701− "version": "3.0.6",
1702− "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz",
1703− "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=",
1704− "dev": true,
1705− "requires": {
1706− "ansi-escapes": "^1.1.0",
1707− "chalk": "^1.0.0",
1708− "cli-cursor": "^2.1.0",
1709− "cli-width": "^2.0.0",
1710− "external-editor": "^2.0.1",
1711− "figures": "^2.0.0",
1712− "lodash": "^4.3.0",
1713− "mute-stream": "0.0.7",
1714− "run-async": "^2.2.0",
1715− "rx": "^4.1.0",
1716− "string-width": "^2.0.0",
1717− "strip-ansi": "^3.0.0",
1718− "through": "^2.3.6"
1719− }
1720− },
1721− "invert-kv": {
1722− "version": "1.0.0",
1723− "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
1724− "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
1725− "dev": true
1726− },
1727− "is-accessor-descriptor": {
1728− "version": "0.1.6",
1729− "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
1730− "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
1731− "dev": true,
1732− "requires": {
1733− "kind-of": "^3.0.2"
1734− }
1735− },
1736− "is-arrayish": {
1737− "version": "0.2.1",
1738− "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
1739− "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
1740− "dev": true
1741− },
1742729 "is-binary-path": {
1743− "version": "1.0.1",
1744− "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
1745− "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
730+ "version": "2.1.0",
731+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
732+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
1746733 "dev": true,
1747734 "requires": {
1748− "binary-extensions": "^1.0.0"
735+ "binary-extensions": "^2.0.0"
1749736 }
1750737 },
1751− "is-buffer": {
1752− "version": "1.1.6",
1753− "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
1754− "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
1755− "dev": true
1756− },
1757738 "is-ci": {
1758− "version": "1.2.1",
1759− "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
1760− "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
1761− "dev": true,
1762− "requires": {
1763− "ci-info": "^1.5.0"
1764− }
1765− },
1766− "is-data-descriptor": {
1767− "version": "0.1.4",
1768− "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
1769− "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
1770− "dev": true,
1771− "requires": {
1772− "kind-of": "^3.0.2"
1773− }
1774− },
1775− "is-descriptor": {
1776− "version": "0.1.6",
1777− "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
1778− "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
1779− "dev": true,
1780− "requires": {
1781− "is-accessor-descriptor": "^0.1.6",
1782− "is-data-descriptor": "^0.1.4",
1783− "kind-of": "^5.0.0"
1784− },
1785− "dependencies": {
1786− "kind-of": {
1787− "version": "5.1.0",
1788− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
1789− "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
1790− "dev": true
1791− }
1792− }
1793− },
1794− "is-dotfile": {
1795− "version": "1.0.3",
1796− "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
1797− "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
1798− "dev": true
1799− },
1800− "is-equal-shallow": {
1801− "version": "0.1.3",
1802− "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
1803− "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
739+ "version": "2.0.0",
740+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
741+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
1804742 "dev": true,
1805743 "requires": {
1806− "is-primitive": "^2.0.0"
744+ "ci-info": "^2.0.0"
1807745 }
1808746 },
1809− "is-extendable": {
1810− "version": "0.1.1",
1811− "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
1812− "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
1813− "dev": true
1814− },
1815747 "is-extglob": {
1816− "version": "1.0.0",
1817− "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
1818− "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
748+ "version": "2.1.1",
749+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
750+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
1819751 "dev": true
1820752 },
1821753 "is-fullwidth-code-point": {
@@ -1825,12 +757,12 @@
1825757 "dev": true
1826758 },
1827759 "is-glob": {
1828− "version": "2.0.1",
1829− "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
1830− "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
760+ "version": "4.0.1",
761+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
762+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
1831763 "dev": true,
1832764 "requires": {
1833− "is-extglob": "^1.0.0"
765+ "is-extglob": "^2.1.1"
1834766 }
1835767 },
1836768 "is-installed-globally": {
@@ -1844,23 +776,20 @@
1844776 }
1845777 },
1846778 "is-npm": {
1847− "version": "1.0.0",
1848− "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
1849− "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=",
779+ "version": "3.0.0",
780+ "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz",
781+ "integrity": "sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==",
1850782 "dev": true
1851783 },
1852784 "is-number": {
1853− "version": "2.1.0",
1854− "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
1855− "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
1856− "dev": true,
1857− "requires": {
1858− "kind-of": "^3.0.2"
1859− }
785+ "version": "7.0.0",
786+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
787+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
788+ "dev": true
1860789 },
1861790 "is-obj": {
1862791 "version": "1.0.1",
1863− "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
792+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
1864793 "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
1865794 "dev": true
1866795 },
@@ -1873,81 +802,22 @@
1873802 "path-is-inside": "^1.0.1"
1874803 }
1875804 },
1876− "is-plain-object": {
1877− "version": "2.0.4",
1878− "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
1879− "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
1880− "dev": true,
1881− "requires": {
1882− "isobject": "^3.0.1"
1883− },
1884− "dependencies": {
1885− "isobject": {
1886− "version": "3.0.1",
1887− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
1888− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
1889− "dev": true
1890− }
1891− }
1892− },
1893− "is-posix-bracket": {
1894− "version": "0.1.1",
1895− "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
1896− "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
1897− "dev": true
1898− },
1899− "is-primitive": {
1900− "version": "2.0.0",
1901− "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
1902− "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
1903− "dev": true
1904− },
1905− "is-promise": {
1906− "version": "2.1.0",
1907− "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
1908− "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
1909− "dev": true
1910− },
1911− "is-redirect": {
1912− "version": "1.0.0",
1913− "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
1914− "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=",
1915− "dev": true
1916− },
1917− "is-retry-allowed": {
1918− "version": "1.2.0",
1919− "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
1920− "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==",
1921− "dev": true
1922− },
1923805 "is-stream": {
1924806 "version": "1.1.0",
1925807 "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
1926808 "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
1927809 "dev": true
1928810 },
1929− "is-utf8": {
1930− "version": "0.2.1",
1931− "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
1932− "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
1933− "dev": true
1934− },
1935− "is-windows": {
1936− "version": "1.0.2",
1937− "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
1938− "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
1939− "dev": true
1940− },
1941811 "is-wsl": {
1942812 "version": "1.1.0",
1943813 "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
1944814 "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
1945815 "dev": true
1946816 },
1947− "isarray": {
1948− "version": "1.0.0",
1949− "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
1950− "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
817+ "is-yarn-global": {
818+ "version": "0.3.0",
819+ "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz",
820+ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==",
1951821 "dev": true
1952822 },
1953823 "isexe": {
@@ -1956,81 +826,67 @@
1956826 "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
1957827 "dev": true
1958828 },
1959− "isobject": {
1960− "version": "2.1.0",
1961− "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
1962− "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
1963− "dev": true,
1964− "requires": {
1965− "isarray": "1.0.0"
1966− }
829+ "json-buffer": {
830+ "version": "3.0.0",
831+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
832+ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
833+ "dev": true
1967834 },
1968835 "jsonfile": {
1969− "version": "2.4.0",
1970− "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
1971− "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
836+ "version": "4.0.0",
837+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
838+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
1972839 "dev": true,
1973840 "requires": {
1974841 "graceful-fs": "^4.1.6"
1975842 }
1976843 },
1977− "kind-of": {
1978− "version": "3.2.2",
1979− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1980− "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1981− "dev": true,
1982− "requires": {
1983− "is-buffer": "^1.1.5"
1984− }
1985− },
1986− "latest-version": {
844+ "keyv": {
1987845 "version": "3.1.0",
1988− "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz",
1989− "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=",
846+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
847+ "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
1990848 "dev": true,
1991849 "requires": {
1992− "package-json": "^4.0.0"
850+ "json-buffer": "3.0.0"
1993851 }
1994852 },
1995− "lcid": {
1996− "version": "1.0.0",
1997− "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
1998− "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
853+ "latest-version": {
854+ "version": "5.1.0",
855+ "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz",
856+ "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==",
1999857 "dev": true,
2000858 "requires": {
2001− "invert-kv": "^1.0.0"
859+ "package-json": "^6.3.0"
2002860 }
2003861 },
2004862 "livereload": {
2005− "version": "0.7.0",
2006− "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.7.0.tgz",
2007− "integrity": "sha512-PHnIGczQEvmCctDvRTWylA+1wSwE0/eFm+LkNhlmlAFus/aCRlVE97UOLOf6TUGLmZyfg7z7twG37ZiOgNJAyQ==",
863+ "version": "0.9.1",
864+ "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.1.tgz",
865+ "integrity": "sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw==",
2008866 "dev": true,
2009867 "requires": {
2010− "chokidar": "^1.7.0",
868+ "chokidar": "^3.3.0",
869+ "livereload-js": "^3.1.0",
2011870 "opts": ">= 1.2.0",
2012− "ws": "^1.1.5"
871+ "ws": "^6.2.1"
2013872 }
2014873 },
2015− "load-json-file": {
2016− "version": "1.1.0",
2017− "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
2018− "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
874+ "livereload-js": {
875+ "version": "3.3.1",
876+ "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.3.1.tgz",
877+ "integrity": "sha512-CBu1gTEfzVhlOK1WASKAAJ9Qx1fHECTq0SUB67sfxwQssopTyvzqTlgl+c0h9pZ6V+Fzd2rc510ppuNusg9teQ==",
878+ "dev": true
879+ },
880+ "locate-path": {
881+ "version": "3.0.0",
882+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
883+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
2019884 "dev": true,
2020885 "requires": {
2021− "graceful-fs": "^4.1.2",
2022− "parse-json": "^2.2.0",
2023− "pify": "^2.0.0",
2024− "pinkie-promise": "^2.0.0",
2025− "strip-bom": "^2.0.0"
886+ "p-locate": "^3.0.0",
887+ "path-exists": "^3.0.0"
2026888 }
2027889 },
2028− "lodash": {
2029− "version": "4.17.15",
2030− "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
2031− "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
2032− "dev": true
2033− },
2034890 "lowercase-keys": {
2035891 "version": "1.0.1",
2036892 "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@@ -2038,124 +894,58 @@
2038894 "dev": true
2039895 },
2040896 "lru-cache": {
2041− "version": "4.1.5",
2042− "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
2043− "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
897+ "version": "5.1.1",
898+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
899+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
2044900 "dev": true,
2045901 "requires": {
2046− "pseudomap": "^1.0.2",
2047− "yallist": "^2.1.2"
902+ "yallist": "^3.0.2"
2048903 }
2049904 },
2050905 "make-dir": {
2051− "version": "1.3.0",
2052− "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
2053− "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
2054− "dev": true,
2055− "requires": {
2056− "pify": "^3.0.0"
2057− },
2058− "dependencies": {
2059− "pify": {
2060− "version": "3.0.0",
2061− "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
2062− "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
2063− "dev": true
2064− }
2065− }
2066− },
2067− "map-cache": {
2068− "version": "0.2.2",
2069− "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
2070− "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
2071− "dev": true
2072− },
2073− "map-visit": {
2074− "version": "1.0.0",
2075− "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
2076− "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
906+ "version": "3.1.0",
907+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
908+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
2077909 "dev": true,
2078910 "requires": {
2079− "object-visit": "^1.0.0"
911+ "semver": "^6.0.0"
2080912 }
2081913 },
2082914 "marked": {
2083− "version": "0.5.2",
2084− "resolved": "https://registry.npmjs.org/marked/-/marked-0.5.2.tgz",
2085− "integrity": "sha512-fdZvBa7/vSQIZCi4uuwo2N3q+7jJURpMVCcbaX0S1Mg65WZ5ilXvC67MviJAsdjqqgD+CEq4RKo5AYGgINkVAA==",
2086− "dev": true
2087− },
2088− "math-random": {
2089− "version": "1.0.4",
2090− "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
2091− "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
915+ "version": "0.7.0",
916+ "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
917+ "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==",
2092918 "dev": true
2093919 },
2094920 "medium-zoom": {
2095− "version": "0.4.0",
2096− "resolved": "http://registry.npmjs.org/medium-zoom/-/medium-zoom-0.4.0.tgz",
2097− "integrity": "sha512-0z7yMfd6I1BTCAa8QaR4cp5AqDkQD571GzhHIbbfefKEssGLSvs+4Xai/itOAncm4FBlF5gUoMQ22yW9/f8Sig==",
921+ "version": "1.0.6",
922+ "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.0.6.tgz",
923+ "integrity": "sha512-UdiUWfvz9fZMg1pzf4dcuqA0W079o0mpqbTnOz5ip4VGYX96QjmbM+OgOU/0uOzAytxC0Ny4z+VcYQnhdifimg==",
2098924 "dev": true
2099925 },
2100− "micromatch": {
2101− "version": "2.3.11",
2102− "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
2103− "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
2104− "dev": true,
2105− "requires": {
2106− "arr-diff": "^2.0.0",
2107− "array-unique": "^0.2.1",
2108− "braces": "^1.8.2",
2109− "expand-brackets": "^0.1.4",
2110− "extglob": "^0.3.1",
2111− "filename-regex": "^2.0.0",
2112− "is-extglob": "^1.0.0",
2113− "is-glob": "^2.0.1",
2114− "kind-of": "^3.0.2",
2115− "normalize-path": "^2.0.1",
2116− "object.omit": "^2.0.0",
2117− "parse-glob": "^3.0.4",
2118− "regex-cache": "^0.4.2"
2119− }
2120− },
2121926 "mime": {
2122927 "version": "1.6.0",
2123928 "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
2124929 "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
2125930 "dev": true
2126931 },
2127− "mimic-fn": {
2128− "version": "1.2.0",
2129− "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
2130− "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
932+ "mimic-response": {
933+ "version": "1.0.1",
934+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
935+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
2131936 "dev": true
2132937 },
2133− "minimist": {
2134− "version": "1.2.0",
2135− "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
2136− "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
938+ "min-indent": {
939+ "version": "1.0.1",
940+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
941+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
2137942 "dev": true
2138943 },
2139− "mixin-deep": {
2140− "version": "1.3.2",
2141− "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
2142− "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
2143− "dev": true,
2144− "requires": {
2145− "for-in": "^1.0.2",
2146− "is-extendable": "^1.0.1"
2147− },
2148− "dependencies": {
2149− "is-extendable": {
2150− "version": "1.0.1",
2151− "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
2152− "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
2153− "dev": true,
2154− "requires": {
2155− "is-plain-object": "^2.0.4"
2156− }
2157− }
2158− }
944+ "minimist": {
945+ "version": "1.2.5",
946+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
947+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
948+ "dev": true
2159949 },
2160950 "ms": {
2161951 "version": "2.0.0",
@@ -2163,58 +953,6 @@
2163953 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
2164954 "dev": true
2165955 },
2166− "mute-stream": {
2167− "version": "0.0.7",
2168− "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
2169− "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
2170− "dev": true
2171− },
2172− "nan": {
2173− "version": "2.14.0",
2174− "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
2175− "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
2176− "dev": true,
2177− "optional": true
2178− },
2179− "nanomatch": {
2180− "version": "1.2.13",
2181− "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
2182− "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
2183− "dev": true,
2184− "requires": {
2185− "arr-diff": "^4.0.0",
2186− "array-unique": "^0.3.2",
2187− "define-property": "^2.0.2",
2188− "extend-shallow": "^3.0.2",
2189− "fragment-cache": "^0.2.1",
2190− "is-windows": "^1.0.2",
2191− "kind-of": "^6.0.2",
2192− "object.pick": "^1.3.0",
2193− "regex-not": "^1.0.0",
2194− "snapdragon": "^0.8.1",
2195− "to-regex": "^3.0.1"
2196− },
2197− "dependencies": {
2198− "arr-diff": {
2199− "version": "4.0.0",
2200− "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
2201− "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
2202− "dev": true
2203− },
2204− "array-unique": {
2205− "version": "0.3.2",
2206− "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
2207− "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
2208− "dev": true
2209− },
2210− "kind-of": {
2211− "version": "6.0.2",
2212− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
2213− "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
2214− "dev": true
2215− }
2216− }
2217− },
2218956 "nested-error-stacks": {
2219957 "version": "2.1.0",
2220958 "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz",
@@ -2222,35 +960,22 @@
2222960 "dev": true
2223961 },
2224962 "node-fetch": {
2225− "version": "1.6.3",
2226− "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz",
2227− "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=",
2228− "dev": true,
2229− "requires": {
2230− "encoding": "^0.1.11",
2231− "is-stream": "^1.0.1"
2232− }
2233− },
2234− "normalize-package-data": {
2235− "version": "2.5.0",
2236− "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
2237− "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
2238− "dev": true,
2239− "requires": {
2240− "hosted-git-info": "^2.1.4",
2241− "resolve": "^1.10.0",
2242− "semver": "2 || 3 || 4 || 5",
2243− "validate-npm-package-license": "^3.0.1"
2244− }
963+ "version": "2.6.0",
964+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
965+ "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
966+ "dev": true
2245967 },
2246968 "normalize-path": {
2247− "version": "2.1.1",
2248− "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
2249− "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
2250− "dev": true,
2251− "requires": {
2252− "remove-trailing-separator": "^1.0.1"
2253− }
969+ "version": "3.0.0",
970+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
971+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
972+ "dev": true
973+ },
974+ "normalize-url": {
975+ "version": "4.5.0",
976+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
977+ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==",
978+ "dev": true
2254979 },
2255980 "npm-run-path": {
2256981 "version": "2.0.2",
@@ -2261,84 +986,6 @@
2261986 "path-key": "^2.0.0"
2262987 }
2263988 },
2264− "number-is-nan": {
2265− "version": "1.0.1",
2266− "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
2267− "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
2268− "dev": true
2269− },
2270− "object-assign": {
2271− "version": "4.1.1",
2272− "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
2273− "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
2274− "dev": true
2275− },
2276− "object-copy": {
2277− "version": "0.1.0",
2278− "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
2279− "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
2280− "dev": true,
2281− "requires": {
2282− "copy-descriptor": "^0.1.0",
2283− "define-property": "^0.2.5",
2284− "kind-of": "^3.0.3"
2285− },
2286− "dependencies": {
2287− "define-property": {
2288− "version": "0.2.5",
2289− "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
2290− "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
2291− "dev": true,
2292− "requires": {
2293− "is-descriptor": "^0.1.0"
2294− }
2295− }
2296− }
2297− },
2298− "object-visit": {
2299− "version": "1.0.1",
2300− "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
2301− "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
2302− "dev": true,
2303− "requires": {
2304− "isobject": "^3.0.0"
2305− },
2306− "dependencies": {
2307− "isobject": {
2308− "version": "3.0.1",
2309− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
2310− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
2311− "dev": true
2312− }
2313− }
2314− },
2315− "object.omit": {
2316− "version": "2.0.1",
2317− "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
2318− "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
2319− "dev": true,
2320− "requires": {
2321− "for-own": "^0.1.4",
2322− "is-extendable": "^0.1.1"
2323− }
2324− },
2325− "object.pick": {
2326− "version": "1.3.0",
2327− "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
2328− "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
2329− "dev": true,
2330− "requires": {
2331− "isobject": "^3.0.1"
2332− },
2333− "dependencies": {
2334− "isobject": {
2335− "version": "3.0.1",
2336− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
2337− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
2338− "dev": true
2339− }
2340− }
2341− },
2342989 "on-finished": {
2343990 "version": "2.3.0",
2344991 "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@@ -2348,147 +995,118 @@
2348995 "ee-first": "1.1.1"
2349996 }
2350997 },
2351− "onetime": {
2352− "version": "2.0.1",
2353− "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
2354− "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
2355− "dev": true,
2356− "requires": {
2357− "mimic-fn": "^1.0.0"
2358− }
2359− },
2360− "opencollective": {
2361− "version": "1.0.3",
2362− "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz",
2363− "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=",
998+ "once": {
999+ "version": "1.4.0",
1000+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1001+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
23641002 "dev": true,
23651003 "requires": {
2366− "babel-polyfill": "6.23.0",
2367− "chalk": "1.1.3",
2368− "inquirer": "3.0.6",
2369− "minimist": "1.2.0",
2370− "node-fetch": "1.6.3",
2371− "opn": "4.0.2"
2372− },
2373− "dependencies": {
2374− "opn": {
2375− "version": "4.0.2",
2376− "resolved": "http://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
2377− "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",
2378− "dev": true,
2379− "requires": {
2380− "object-assign": "^4.0.1",
2381− "pinkie-promise": "^2.0.0"
2382− }
2383− }
1004+ "wrappy": "1"
23841005 }
23851006 },
2386− "opn": {
2387− "version": "5.5.0",
2388− "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
2389− "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
1007+ "open": {
1008+ "version": "6.4.0",
1009+ "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz",
1010+ "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==",
23901011 "dev": true,
23911012 "requires": {
23921013 "is-wsl": "^1.1.0"
23931014 }
23941015 },
2395− "options": {
2396− "version": "0.0.6",
2397− "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
2398− "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=",
1016+ "opencollective-postinstall": {
1017+ "version": "2.0.3",
1018+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
1019+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
23991020 "dev": true
24001021 },
24011022 "opts": {
2402− "version": "1.2.7",
2403− "resolved": "https://registry.npmjs.org/opts/-/opts-1.2.7.tgz",
2404− "integrity": "sha512-hwZhzGGG/GQ7igxAVFOEun2N4fWul31qE9nfBdCnZGQCB5+L7tN9xZ+94B4aUpLOJx/of3zZs5XsuubayQYQjA==",
1023+ "version": "2.0.0",
1024+ "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.0.tgz",
1025+ "integrity": "sha512-rPleeyX48sBEc4aj7rAok5dCbvRdYpdbIdSRR4gnIK98a7Rvd4l3wlv4YHQr2mwPQTpKQiw8uipi/WoyItDINg==",
24051026 "dev": true
24061027 },
2407− "os-locale": {
2408− "version": "1.4.0",
2409− "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
2410− "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
1028+ "p-cancelable": {
1029+ "version": "1.1.0",
1030+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
1031+ "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
1032+ "dev": true
1033+ },
1034+ "p-event": {
1035+ "version": "4.2.0",
1036+ "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
1037+ "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==",
24111038 "dev": true,
24121039 "requires": {
2413− "lcid": "^1.0.0"
1040+ "p-timeout": "^3.1.0"
24141041 }
24151042 },
2416− "os-tmpdir": {
2417− "version": "1.0.2",
2418− "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
2419− "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
2420− "dev": true
2421− },
24221043 "p-finally": {
24231044 "version": "1.0.0",
24241045 "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
24251046 "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
24261047 "dev": true
24271048 },
2428− "package-json": {
2429− "version": "4.0.1",
2430− "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
2431− "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
1049+ "p-limit": {
1050+ "version": "2.3.0",
1051+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
1052+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
24321053 "dev": true,
24331054 "requires": {
2434− "got": "^6.7.1",
2435− "registry-auth-token": "^3.0.1",
2436− "registry-url": "^3.0.3",
2437− "semver": "^5.1.0"
1055+ "p-try": "^2.0.0"
24381056 }
24391057 },
2440− "parent-require": {
2441− "version": "1.0.0",
2442− "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz",
2443− "integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc=",
2444− "dev": true
1058+ "p-locate": {
1059+ "version": "3.0.0",
1060+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
1061+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
1062+ "dev": true,
1063+ "requires": {
1064+ "p-limit": "^2.0.0"
1065+ }
24451066 },
2446− "parse-glob": {
2447− "version": "3.0.4",
2448− "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
2449− "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
1067+ "p-timeout": {
1068+ "version": "3.2.0",
1069+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
1070+ "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
24501071 "dev": true,
24511072 "requires": {
2452− "glob-base": "^0.3.0",
2453− "is-dotfile": "^1.0.0",
2454− "is-extglob": "^1.0.0",
2455− "is-glob": "^2.0.0"
1073+ "p-finally": "^1.0.0"
24561074 }
24571075 },
2458− "parse-json": {
1076+ "p-try": {
24591077 "version": "2.2.0",
2460− "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
2461− "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
1078+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
1079+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
1080+ "dev": true
1081+ },
1082+ "package-json": {
1083+ "version": "6.5.0",
1084+ "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
1085+ "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==",
24621086 "dev": true,
24631087 "requires": {
2464− "error-ex": "^1.2.0"
1088+ "got": "^9.6.0",
1089+ "registry-auth-token": "^4.0.0",
1090+ "registry-url": "^5.0.0",
1091+ "semver": "^6.2.0"
24651092 }
24661093 },
1094+ "parent-require": {
1095+ "version": "1.0.0",
1096+ "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz",
1097+ "integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc=",
1098+ "dev": true
1099+ },
24671100 "parseurl": {
24681101 "version": "1.3.3",
24691102 "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
24701103 "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
24711104 "dev": true
24721105 },
2473− "pascalcase": {
2474− "version": "0.1.1",
2475− "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
2476− "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
2477− "dev": true
2478− },
24791106 "path-exists": {
2480− "version": "2.1.0",
2481− "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
2482− "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
2483− "dev": true,
2484− "requires": {
2485− "pinkie-promise": "^2.0.0"
2486− }
2487− },
2488− "path-is-absolute": {
2489− "version": "1.0.1",
2490− "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
2491− "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1107+ "version": "3.0.0",
1108+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
1109+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
24921110 "dev": true
24931111 },
24941112 "path-is-inside": {
@@ -2503,106 +1121,47 @@
25031121 "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
25041122 "dev": true
25051123 },
2506− "path-parse": {
2507− "version": "1.0.6",
2508− "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
2509− "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
1124+ "picomatch": {
1125+ "version": "2.2.2",
1126+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
1127+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
25101128 "dev": true
25111129 },
2512− "path-type": {
2513− "version": "1.1.0",
2514− "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
2515− "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
2516− "dev": true,
2517− "requires": {
2518− "graceful-fs": "^4.1.2",
2519− "pify": "^2.0.0",
2520− "pinkie-promise": "^2.0.0"
2521− }
2522− },
25231130 "pify": {
2524− "version": "2.3.0",
2525− "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
2526− "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
2527− "dev": true
2528− },
2529− "pinkie": {
2530− "version": "2.0.4",
2531− "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
2532− "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
2533− "dev": true
2534− },
2535− "pinkie-promise": {
2536− "version": "2.0.1",
2537− "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
2538− "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
2539− "dev": true,
2540− "requires": {
2541− "pinkie": "^2.0.0"
2542− }
2543− },
2544− "posix-character-classes": {
2545− "version": "0.1.1",
2546− "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
2547− "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
1131+ "version": "3.0.0",
1132+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
1133+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
25481134 "dev": true
25491135 },
25501136 "prepend-http": {
2551− "version": "1.0.4",
2552− "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
2553− "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
2554− "dev": true
2555− },
2556− "preserve": {
2557− "version": "0.2.0",
2558− "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
2559− "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
1137+ "version": "2.0.0",
1138+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
1139+ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
25601140 "dev": true
25611141 },
25621142 "prismjs": {
2563− "version": "1.17.1",
2564− "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz",
2565− "integrity": "sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q==",
1143+ "version": "1.21.0",
1144+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.21.0.tgz",
1145+ "integrity": "sha512-uGdSIu1nk3kej2iZsLyDoJ7e9bnPzIgY0naW/HdknGj61zScaprVEVGHrPoXqI+M9sP0NDnTK2jpkvmldpuqDw==",
25661146 "dev": true,
25671147 "requires": {
25681148 "clipboard": "^2.0.0"
25691149 }
25701150 },
2571− "process-nextick-args": {
2572− "version": "2.0.1",
2573− "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
2574− "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
2575− "dev": true
2576− },
25771151 "pseudomap": {
25781152 "version": "1.0.2",
25791153 "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
25801154 "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
25811155 "dev": true
25821156 },
2583− "randomatic": {
2584− "version": "3.1.1",
2585− "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
2586− "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
1157+ "pump": {
1158+ "version": "3.0.0",
1159+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
1160+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
25871161 "dev": true,
25881162 "requires": {
2589− "is-number": "^4.0.0",
2590− "kind-of": "^6.0.0",
2591− "math-random": "^1.0.1"
2592− },
2593− "dependencies": {
2594− "is-number": {
2595− "version": "4.0.0",
2596− "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
2597− "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
2598− "dev": true
2599− },
2600− "kind-of": {
2601− "version": "6.0.2",
2602− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
2603− "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
2604− "dev": true
2605− }
1163+ "end-of-stream": "^1.1.0",
1164+ "once": "^1.3.1"
26061165 }
26071166 },
26081167 "range-parser": {
@@ -2623,399 +1182,33 @@
26231182 "strip-json-comments": "~2.0.1"
26241183 }
26251184 },
2626− "read-pkg": {
2627− "version": "1.1.0",
2628− "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
2629− "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
2630− "dev": true,
2631− "requires": {
2632− "load-json-file": "^1.0.0",
2633− "normalize-package-data": "^2.3.2",
2634− "path-type": "^1.0.0"
2635− }
2636− },
2637− "read-pkg-up": {
2638− "version": "1.0.1",
2639− "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
2640− "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
2641− "dev": true,
2642− "requires": {
2643− "find-up": "^1.0.0",
2644− "read-pkg": "^1.0.0"
2645− }
2646− },
2647− "readable-stream": {
2648− "version": "2.3.6",
2649− "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
2650− "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
2651− "dev": true,
2652− "requires": {
2653− "core-util-is": "~1.0.0",
2654− "inherits": "~2.0.3",
2655− "isarray": "~1.0.0",
2656− "process-nextick-args": "~2.0.0",
2657− "safe-buffer": "~5.1.1",
2658− "string_decoder": "~1.1.1",
2659− "util-deprecate": "~1.0.1"
2660− },
2661− "dependencies": {
2662− "safe-buffer": {
2663− "version": "5.1.2",
2664− "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
2665− "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
2666− "dev": true
2667− }
2668− }
2669− },
26701185 "readdirp": {
2671− "version": "2.2.1",
2672− "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
2673− "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
2674− "dev": true,
2675− "requires": {
2676− "graceful-fs": "^4.1.11",
2677− "micromatch": "^3.1.10",
2678− "readable-stream": "^2.0.2"
2679− },
2680− "dependencies": {
2681− "arr-diff": {
2682− "version": "4.0.0",
2683− "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
2684− "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
2685− "dev": true
2686− },
2687− "array-unique": {
2688− "version": "0.3.2",
2689− "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
2690− "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
2691− "dev": true
2692− },
2693− "braces": {
2694− "version": "2.3.2",
2695− "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
2696− "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
2697− "dev": true,
2698− "requires": {
2699− "arr-flatten": "^1.1.0",
2700− "array-unique": "^0.3.2",
2701− "extend-shallow": "^2.0.1",
2702− "fill-range": "^4.0.0",
2703− "isobject": "^3.0.1",
2704− "repeat-element": "^1.1.2",
2705− "snapdragon": "^0.8.1",
2706− "snapdragon-node": "^2.0.1",
2707− "split-string": "^3.0.2",
2708− "to-regex": "^3.0.1"
2709− },
2710− "dependencies": {
2711− "extend-shallow": {
2712− "version": "2.0.1",
2713− "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
2714− "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
2715− "dev": true,
2716− "requires": {
2717− "is-extendable": "^0.1.0"
2718− }
2719− }
2720− }
2721− },
2722− "expand-brackets": {
2723− "version": "2.1.4",
2724− "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
2725− "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
2726− "dev": true,
2727− "requires": {
2728− "debug": "^2.3.3",
2729− "define-property": "^0.2.5",
2730− "extend-shallow": "^2.0.1",
2731− "posix-character-classes": "^0.1.0",
2732− "regex-not": "^1.0.0",
2733− "snapdragon": "^0.8.1",
2734− "to-regex": "^3.0.1"
2735− },
2736− "dependencies": {
2737− "define-property": {
2738− "version": "0.2.5",
2739− "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
2740− "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
2741− "dev": true,
2742− "requires": {
2743− "is-descriptor": "^0.1.0"
2744− }
2745− },
2746− "extend-shallow": {
2747− "version": "2.0.1",
2748− "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
2749− "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
2750− "dev": true,
2751− "requires": {
2752− "is-extendable": "^0.1.0"
2753− }
2754− },
2755− "is-accessor-descriptor": {
2756− "version": "0.1.6",
2757− "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
2758− "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
2759− "dev": true,
2760− "requires": {
2761− "kind-of": "^3.0.2"
2762− },
2763− "dependencies": {
2764− "kind-of": {
2765− "version": "3.2.2",
2766− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
2767− "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
2768− "dev": true,
2769− "requires": {
2770− "is-buffer": "^1.1.5"
2771− }
2772− }
2773− }
2774− },
2775− "is-data-descriptor": {
2776− "version": "0.1.4",
2777− "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
2778− "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
2779− "dev": true,
2780− "requires": {
2781− "kind-of": "^3.0.2"
2782− },
2783− "dependencies": {
2784− "kind-of": {
2785− "version": "3.2.2",
2786− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
2787− "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
2788− "dev": true,
2789− "requires": {
2790− "is-buffer": "^1.1.5"
2791− }
2792− }
2793− }
2794− },
2795− "is-descriptor": {
2796− "version": "0.1.6",
2797− "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
2798− "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
2799− "dev": true,
2800− "requires": {
2801− "is-accessor-descriptor": "^0.1.6",
2802− "is-data-descriptor": "^0.1.4",
2803− "kind-of": "^5.0.0"
2804− }
2805− },
2806− "kind-of": {
2807− "version": "5.1.0",
2808− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
2809− "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
2810− "dev": true
2811− }
2812− }
2813− },
2814− "extglob": {
2815− "version": "2.0.4",
2816− "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
2817− "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
2818− "dev": true,
2819− "requires": {
2820− "array-unique": "^0.3.2",
2821− "define-property": "^1.0.0",
2822− "expand-brackets": "^2.1.4",
2823− "extend-shallow": "^2.0.1",
2824− "fragment-cache": "^0.2.1",
2825− "regex-not": "^1.0.0",
2826− "snapdragon": "^0.8.1",
2827− "to-regex": "^3.0.1"
2828− },
2829− "dependencies": {
2830− "define-property": {
2831− "version": "1.0.0",
2832− "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
2833− "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
2834− "dev": true,
2835− "requires": {
2836− "is-descriptor": "^1.0.0"
2837− }
2838− },
2839− "extend-shallow": {
2840− "version": "2.0.1",
2841− "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
2842− "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
2843− "dev": true,
2844− "requires": {
2845− "is-extendable": "^0.1.0"
2846− }
2847− }
2848− }
2849− },
2850− "fill-range": {
2851− "version": "4.0.0",
2852− "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
2853− "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
2854− "dev": true,
2855− "requires": {
2856− "extend-shallow": "^2.0.1",
2857− "is-number": "^3.0.0",
2858− "repeat-string": "^1.6.1",
2859− "to-regex-range": "^2.1.0"
2860− },
2861− "dependencies": {
2862− "extend-shallow": {
2863− "version": "2.0.1",
2864− "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
2865− "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
2866− "dev": true,
2867− "requires": {
2868− "is-extendable": "^0.1.0"
2869− }
2870− }
2871− }
2872− },
2873− "is-accessor-descriptor": {
2874− "version": "1.0.0",
2875− "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
2876− "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
2877− "dev": true,
2878− "requires": {
2879− "kind-of": "^6.0.0"
2880− }
2881− },
2882− "is-data-descriptor": {
2883− "version": "1.0.0",
2884− "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
2885− "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
2886− "dev": true,
2887− "requires": {
2888− "kind-of": "^6.0.0"
2889− }
2890− },
2891− "is-descriptor": {
2892− "version": "1.0.2",
2893− "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
2894− "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
2895− "dev": true,
2896− "requires": {
2897− "is-accessor-descriptor": "^1.0.0",
2898− "is-data-descriptor": "^1.0.0",
2899− "kind-of": "^6.0.2"
2900− }
2901− },
2902− "is-number": {
2903− "version": "3.0.0",
2904− "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
2905− "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
2906− "dev": true,
2907− "requires": {
2908− "kind-of": "^3.0.2"
2909− },
2910− "dependencies": {
2911− "kind-of": {
2912− "version": "3.2.2",
2913− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
2914− "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
2915− "dev": true,
2916− "requires": {
2917− "is-buffer": "^1.1.5"
2918− }
2919− }
2920− }
2921− },
2922− "isobject": {
2923− "version": "3.0.1",
2924− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
2925− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
2926− "dev": true
2927− },
2928− "kind-of": {
2929− "version": "6.0.2",
2930− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
2931− "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
2932− "dev": true
2933− },
2934− "micromatch": {
2935− "version": "3.1.10",
2936− "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
2937− "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
2938− "dev": true,
2939− "requires": {
2940− "arr-diff": "^4.0.0",
2941− "array-unique": "^0.3.2",
2942− "braces": "^2.3.1",
2943− "define-property": "^2.0.2",
2944− "extend-shallow": "^3.0.2",
2945− "extglob": "^2.0.4",
2946− "fragment-cache": "^0.2.1",
2947− "kind-of": "^6.0.2",
2948− "nanomatch": "^1.2.9",
2949− "object.pick": "^1.3.0",
2950− "regex-not": "^1.0.0",
2951− "snapdragon": "^0.8.1",
2952− "to-regex": "^3.0.2"
2953− }
2954− }
2955− }
2956− },
2957− "regenerator-runtime": {
2958− "version": "0.10.5",
2959− "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
2960− "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
2961− "dev": true
2962− },
2963− "regex-cache": {
2964− "version": "0.4.4",
2965− "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
2966− "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
2967− "dev": true,
2968− "requires": {
2969− "is-equal-shallow": "^0.1.3"
2970− }
2971− },
2972− "regex-not": {
2973− "version": "1.0.2",
2974− "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
2975− "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
1186+ "version": "3.4.0",
1187+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
1188+ "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
29761189 "dev": true,
29771190 "requires": {
2978− "extend-shallow": "^3.0.2",
2979− "safe-regex": "^1.1.0"
1191+ "picomatch": "^2.2.1"
29801192 }
29811193 },
29821194 "registry-auth-token": {
2983− "version": "3.4.0",
2984− "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz",
2985− "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
1195+ "version": "4.2.0",
1196+ "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz",
1197+ "integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==",
29861198 "dev": true,
29871199 "requires": {
2988− "rc": "^1.1.6",
2989− "safe-buffer": "^5.0.1"
1200+ "rc": "^1.2.8"
29901201 }
29911202 },
29921203 "registry-url": {
2993− "version": "3.1.0",
2994− "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
2995− "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
1204+ "version": "5.1.0",
1205+ "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz",
1206+ "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==",
29961207 "dev": true,
29971208 "requires": {
2998− "rc": "^1.0.1"
1209+ "rc": "^1.2.8"
29991210 }
30001211 },
3001− "remove-trailing-separator": {
3002− "version": "1.1.0",
3003− "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
3004− "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
3005− "dev": true
3006− },
3007− "repeat-element": {
3008− "version": "1.1.3",
3009− "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
3010− "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
3011− "dev": true
3012− },
3013− "repeat-string": {
3014− "version": "1.6.1",
3015− "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
3016− "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
3017− "dev": true
3018− },
30191212 "require-directory": {
30201213 "version": "2.1.1",
30211214 "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -3023,84 +1216,26 @@
30231216 "dev": true
30241217 },
30251218 "require-main-filename": {
3026− "version": "1.0.1",
3027− "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
3028− "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
3029− "dev": true
3030− },
3031− "resolve": {
3032− "version": "1.12.0",
3033− "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
3034− "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
3035− "dev": true,
3036− "requires": {
3037− "path-parse": "^1.0.6"
3038− }
3039− },
3040− "resolve-pathname": {
3041− "version": "2.2.0",
3042− "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
3043− "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==",
3044− "dev": true
3045− },
3046− "resolve-url": {
3047− "version": "0.2.1",
3048− "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
3049− "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
3050− "dev": true
3051− },
3052− "restore-cursor": {
30531219 "version": "2.0.0",
3054− "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
3055− "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
3056− "dev": true,
3057− "requires": {
3058− "onetime": "^2.0.0",
3059− "signal-exit": "^3.0.2"
3060− }
3061− },
3062− "ret": {
3063− "version": "0.1.15",
3064− "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
3065− "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
1220+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
1221+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
30661222 "dev": true
30671223 },
3068− "run-async": {
3069− "version": "2.3.0",
3070− "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
3071− "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
3072− "dev": true,
3073− "requires": {
3074− "is-promise": "^2.1.0"
3075− }
3076− },
3077− "rx": {
3078− "version": "4.1.0",
3079− "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz",
3080− "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=",
3081− "dev": true
3082− },
3083− "safe-buffer": {
3084− "version": "5.2.0",
3085− "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
3086− "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
1224+ "resolve-pathname": {
1225+ "version": "3.0.0",
1226+ "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
1227+ "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==",
30871228 "dev": true
30881229 },
3089− "safe-regex": {
3090− "version": "1.1.0",
3091− "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
3092− "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
1230+ "responselike": {
1231+ "version": "1.0.2",
1232+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
1233+ "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
30931234 "dev": true,
30941235 "requires": {
3095− "ret": "~0.1.10"
1236+ "lowercase-keys": "^1.0.0"
30961237 }
30971238 },
3098− "safer-buffer": {
3099− "version": "2.1.2",
3100− "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
3101− "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
3102− "dev": true
3103− },
31041239 "select": {
31051240 "version": "1.1.2",
31061241 "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
@@ -3109,9 +1244,9 @@
31091244 "optional": true
31101245 },
31111246 "semver": {
3112− "version": "5.7.1",
3113− "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
3114− "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1247+ "version": "6.3.0",
1248+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
1249+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
31151250 "dev": true
31161251 },
31171252 "semver-diff": {
@@ -3121,6 +1256,14 @@
31211256 "dev": true,
31221257 "requires": {
31231258 "semver": "^5.0.3"
1259+ },
1260+ "dependencies": {
1261+ "semver": {
1262+ "version": "5.7.1",
1263+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1264+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1265+ "dev": true
1266+ }
31241267 }
31251268 },
31261269 "send": {
@@ -3152,268 +1295,50 @@
31521295 }
31531296 }
31541297 },
3155− "serve-static": {
3156− "version": "1.14.1",
3157− "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
3158− "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
3159− "dev": true,
3160− "requires": {
3161− "encodeurl": "~1.0.2",
3162− "escape-html": "~1.0.3",
3163− "parseurl": "~1.3.3",
3164− "send": "0.17.1"
3165− }
3166− },
3167− "set-blocking": {
3168− "version": "2.0.0",
3169− "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
3170− "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
3171− "dev": true
3172− },
3173− "set-value": {
3174− "version": "2.0.1",
3175− "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
3176− "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
3177− "dev": true,
3178− "requires": {
3179− "extend-shallow": "^2.0.1",
3180− "is-extendable": "^0.1.1",
3181− "is-plain-object": "^2.0.3",
3182− "split-string": "^3.0.1"
3183− },
3184− "dependencies": {
3185− "extend-shallow": {
3186− "version": "2.0.1",
3187− "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
3188− "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
3189− "dev": true,
3190− "requires": {
3191− "is-extendable": "^0.1.0"
3192− }
3193− }
3194− }
3195− },
3196− "setprototypeof": {
3197− "version": "1.1.1",
3198− "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
3199− "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
3200− "dev": true
3201− },
3202− "shebang-command": {
3203− "version": "1.2.0",
3204− "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
3205− "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
3206− "dev": true,
3207− "requires": {
3208− "shebang-regex": "^1.0.0"
3209− }
3210− },
3211− "shebang-regex": {
3212− "version": "1.0.0",
3213− "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
3214− "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
3215− "dev": true
3216− },
3217− "signal-exit": {
3218− "version": "3.0.2",
3219− "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
3220− "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
3221− "dev": true
3222− },
3223− "snapdragon": {
3224− "version": "0.8.2",
3225− "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
3226− "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
3227− "dev": true,
3228− "requires": {
3229− "base": "^0.11.1",
3230− "debug": "^2.2.0",
3231− "define-property": "^0.2.5",
3232− "extend-shallow": "^2.0.1",
3233− "map-cache": "^0.2.2",
3234− "source-map": "^0.5.6",
3235− "source-map-resolve": "^0.5.0",
3236− "use": "^3.1.0"
3237− },
3238− "dependencies": {
3239− "define-property": {
3240− "version": "0.2.5",
3241− "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
3242− "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
3243− "dev": true,
3244− "requires": {
3245− "is-descriptor": "^0.1.0"
3246− }
3247− },
3248− "extend-shallow": {
3249− "version": "2.0.1",
3250− "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
3251− "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
3252− "dev": true,
3253− "requires": {
3254− "is-extendable": "^0.1.0"
3255− }
3256− }
3257− }
3258− },
3259− "snapdragon-node": {
3260− "version": "2.1.1",
3261− "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
3262− "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
3263− "dev": true,
3264− "requires": {
3265− "define-property": "^1.0.0",
3266− "isobject": "^3.0.0",
3267− "snapdragon-util": "^3.0.1"
3268− },
3269− "dependencies": {
3270− "define-property": {
3271− "version": "1.0.0",
3272− "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
3273− "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
3274− "dev": true,
3275− "requires": {
3276− "is-descriptor": "^1.0.0"
3277− }
3278− },
3279− "is-accessor-descriptor": {
3280− "version": "1.0.0",
3281− "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
3282− "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
3283− "dev": true,
3284− "requires": {
3285− "kind-of": "^6.0.0"
3286− }
3287− },
3288− "is-data-descriptor": {
3289− "version": "1.0.0",
3290− "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
3291− "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
3292− "dev": true,
3293− "requires": {
3294− "kind-of": "^6.0.0"
3295− }
3296− },
3297− "is-descriptor": {
3298− "version": "1.0.2",
3299− "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
3300− "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
3301− "dev": true,
3302− "requires": {
3303− "is-accessor-descriptor": "^1.0.0",
3304− "is-data-descriptor": "^1.0.0",
3305− "kind-of": "^6.0.2"
3306− }
3307− },
3308− "isobject": {
3309− "version": "3.0.1",
3310− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
3311− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
3312− "dev": true
3313− },
3314− "kind-of": {
3315− "version": "6.0.2",
3316− "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
3317− "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
3318− "dev": true
3319− }
3320− }
3321− },
3322− "snapdragon-util": {
3323− "version": "3.0.1",
3324− "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
3325− "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
3326− "dev": true,
3327− "requires": {
3328− "kind-of": "^3.2.0"
3329− }
3330− },
3331− "source-map": {
3332− "version": "0.5.7",
3333− "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
3334− "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
3335− "dev": true
3336− },
3337− "source-map-resolve": {
3338− "version": "0.5.2",
3339− "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
3340− "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
3341− "dev": true,
3342− "requires": {
3343− "atob": "^2.1.1",
3344− "decode-uri-component": "^0.2.0",
3345− "resolve-url": "^0.2.1",
3346− "source-map-url": "^0.4.0",
3347− "urix": "^0.1.0"
3348− }
3349− },
3350− "source-map-url": {
3351− "version": "0.4.0",
3352− "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
3353− "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
3354− "dev": true
3355− },
3356− "spdx-correct": {
3357− "version": "3.1.0",
3358− "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
3359− "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
1298+ "serve-static": {
1299+ "version": "1.14.1",
1300+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
1301+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
33601302 "dev": true,
33611303 "requires": {
3362− "spdx-expression-parse": "^3.0.0",
3363− "spdx-license-ids": "^3.0.0"
1304+ "encodeurl": "~1.0.2",
1305+ "escape-html": "~1.0.3",
1306+ "parseurl": "~1.3.3",
1307+ "send": "0.17.1"
33641308 }
33651309 },
3366− "spdx-exceptions": {
3367− "version": "2.2.0",
3368− "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
3369− "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
1310+ "set-blocking": {
1311+ "version": "2.0.0",
1312+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
1313+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
33701314 "dev": true
33711315 },
3372− "spdx-expression-parse": {
3373− "version": "3.0.0",
3374− "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
3375− "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
3376− "dev": true,
3377− "requires": {
3378− "spdx-exceptions": "^2.1.0",
3379− "spdx-license-ids": "^3.0.0"
3380− }
3381− },
3382− "spdx-license-ids": {
3383− "version": "3.0.5",
3384− "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
3385− "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
1316+ "setprototypeof": {
1317+ "version": "1.1.1",
1318+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
1319+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
33861320 "dev": true
33871321 },
3388− "split-string": {
3389− "version": "3.1.0",
3390− "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
3391− "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
1322+ "shebang-command": {
1323+ "version": "1.2.0",
1324+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
1325+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
33921326 "dev": true,
33931327 "requires": {
3394− "extend-shallow": "^3.0.0"
1328+ "shebang-regex": "^1.0.0"
33951329 }
33961330 },
3397− "static-extend": {
3398− "version": "0.1.2",
3399− "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
3400− "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
3401− "dev": true,
3402− "requires": {
3403− "define-property": "^0.2.5",
3404− "object-copy": "^0.1.0"
3405− },
3406− "dependencies": {
3407− "define-property": {
3408− "version": "0.2.5",
3409− "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
3410− "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
3411− "dev": true,
3412− "requires": {
3413− "is-descriptor": "^0.1.0"
3414− }
3415− }
3416− }
1331+ "shebang-regex": {
1332+ "version": "1.0.0",
1333+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
1334+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
1335+ "dev": true
1336+ },
1337+ "signal-exit": {
1338+ "version": "3.0.3",
1339+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
1340+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
1341+ "dev": true
34171342 },
34181343 "statuses": {
34191344 "version": "1.5.0",
@@ -3422,73 +1347,40 @@
34221347 "dev": true
34231348 },
34241349 "string-width": {
3425− "version": "2.1.1",
3426− "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
3427− "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
1350+ "version": "3.1.0",
1351+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
1352+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
34281353 "dev": true,
34291354 "requires": {
1355+ "emoji-regex": "^7.0.1",
34301356 "is-fullwidth-code-point": "^2.0.0",
3431− "strip-ansi": "^4.0.0"
3432− },
3433− "dependencies": {
3434− "ansi-regex": {
3435− "version": "3.0.0",
3436− "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
3437− "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
3438− "dev": true
3439− },
3440− "strip-ansi": {
3441− "version": "4.0.0",
3442− "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
3443− "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
3444− "dev": true,
3445− "requires": {
3446− "ansi-regex": "^3.0.0"
3447− }
3448− }
3449− }
3450− },
3451− "string_decoder": {
3452− "version": "1.1.1",
3453− "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
3454− "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
3455− "dev": true,
3456− "requires": {
3457− "safe-buffer": "~5.1.0"
3458− },
3459− "dependencies": {
3460− "safe-buffer": {
3461− "version": "5.1.2",
3462− "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
3463− "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
3464− "dev": true
3465− }
1357+ "strip-ansi": "^5.1.0"
34661358 }
34671359 },
34681360 "strip-ansi": {
3469− "version": "3.0.1",
3470− "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
3471− "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
3472− "dev": true,
3473− "requires": {
3474− "ansi-regex": "^2.0.0"
3475− }
3476− },
3477− "strip-bom": {
3478− "version": "2.0.0",
3479− "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
3480− "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
1361+ "version": "5.2.0",
1362+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
1363+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
34811364 "dev": true,
34821365 "requires": {
3483− "is-utf8": "^0.2.0"
1366+ "ansi-regex": "^4.1.0"
34841367 }
34851368 },
34861369 "strip-eof": {
34871370 "version": "1.0.0",
3488− "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
1371+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
34891372 "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
34901373 "dev": true
34911374 },
1375+ "strip-indent": {
1376+ "version": "3.0.0",
1377+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
1378+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
1379+ "dev": true,
1380+ "requires": {
1381+ "min-indent": "^1.0.0"
1382+ }
1383+ },
34921384 "strip-json-comments": {
34931385 "version": "2.0.1",
34941386 "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -3496,10 +1388,13 @@
34961388 "dev": true
34971389 },
34981390 "supports-color": {
3499− "version": "2.0.0",
3500− "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
3501− "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
3502− "dev": true
1391+ "version": "5.5.0",
1392+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1393+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1394+ "dev": true,
1395+ "requires": {
1396+ "has-flag": "^3.0.0"
1397+ }
35031398 },
35041399 "term-size": {
35051400 "version": "1.2.0",
@@ -3510,18 +1405,6 @@
35101405 "execa": "^0.7.0"
35111406 }
35121407 },
3513− "through": {
3514− "version": "2.3.8",
3515− "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
3516− "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
3517− "dev": true
3518− },
3519− "timed-out": {
3520− "version": "4.0.1",
3521− "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
3522− "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
3523− "dev": true
3524− },
35251408 "tiny-emitter": {
35261409 "version": "2.1.0",
35271410 "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
@@ -3530,60 +1413,24 @@
35301413 "optional": true
35311414 },
35321415 "tinydate": {
3533− "version": "1.2.0",
3534− "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.2.0.tgz",
3535− "integrity": "sha512-3GwPk8VhDFnUZ2TrgkhXJs6hcMAIIw4x/xkz+ayK6dGoQmp2nUwKzBXK0WnMsqkh6vfUhpqQicQF3rbshfyJkg==",
1416+ "version": "1.3.0",
1417+ "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz",
1418+ "integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==",
35361419 "dev": true
35371420 },
3538− "tmp": {
3539− "version": "0.0.33",
3540− "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
3541− "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
3542− "dev": true,
3543− "requires": {
3544− "os-tmpdir": "~1.0.2"
3545− }
3546− },
3547− "to-object-path": {
3548− "version": "0.3.0",
3549− "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
3550− "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
3551− "dev": true,
3552− "requires": {
3553− "kind-of": "^3.0.2"
3554− }
3555− },
3556− "to-regex": {
3557− "version": "3.0.2",
3558− "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
3559− "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
3560− "dev": true,
3561− "requires": {
3562− "define-property": "^2.0.2",
3563− "extend-shallow": "^3.0.2",
3564− "regex-not": "^1.0.2",
3565− "safe-regex": "^1.1.0"
3566− }
1421+ "to-readable-stream": {
1422+ "version": "1.0.0",
1423+ "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
1424+ "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==",
1425+ "dev": true
35671426 },
35681427 "to-regex-range": {
3569− "version": "2.1.1",
3570− "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
3571− "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
1428+ "version": "5.0.1",
1429+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1430+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
35721431 "dev": true,
35731432 "requires": {
3574− "is-number": "^3.0.0",
3575− "repeat-string": "^1.6.1"
3576− },
3577− "dependencies": {
3578− "is-number": {
3579− "version": "3.0.0",
3580− "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
3581− "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
3582− "dev": true,
3583− "requires": {
3584− "kind-of": "^3.0.2"
3585− }
3586− }
1433+ "is-number": "^7.0.0"
35871434 }
35881435 },
35891436 "toidentifier": {
@@ -3598,24 +1445,12 @@
35981445 "integrity": "sha512-aSiJz7rGWNAQq7hjMK9ZYDuEawXupcCWgl3woQQSoDP2Oh8O4srWb/uO1PzzHIsrPEOqrjJ2sUb9FERfzuBabQ==",
35991446 "dev": true
36001447 },
3601− "ultron": {
3602− "version": "1.0.2",
3603− "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
3604− "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=",
1448+ "type-fest": {
1449+ "version": "0.3.1",
1450+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz",
1451+ "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==",
36051452 "dev": true
36061453 },
3607− "union-value": {
3608− "version": "1.0.1",
3609− "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
3610− "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
3611− "dev": true,
3612− "requires": {
3613− "arr-union": "^3.1.0",
3614− "get-value": "^2.0.6",
3615− "is-extendable": "^0.1.1",
3616− "set-value": "^2.0.1"
3617− }
3618− },
36191454 "unique-string": {
36201455 "version": "1.0.0",
36211456 "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz",
@@ -3625,156 +1460,53 @@
36251460 "crypto-random-string": "^1.0.0"
36261461 }
36271462 },
1463+ "universalify": {
1464+ "version": "0.1.2",
1465+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
1466+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
1467+ "dev": true
1468+ },
36281469 "unpipe": {
36291470 "version": "1.0.0",
36301471 "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
36311472 "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
36321473 "dev": true
36331474 },
3634− "unset-value": {
3635− "version": "1.0.0",
3636− "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
3637− "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
3638− "dev": true,
3639− "requires": {
3640− "has-value": "^0.3.1",
3641− "isobject": "^3.0.0"
3642− },
3643− "dependencies": {
3644− "has-value": {
3645− "version": "0.3.1",
3646− "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
3647− "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
3648− "dev": true,
3649− "requires": {
3650− "get-value": "^2.0.3",
3651− "has-values": "^0.1.4",
3652− "isobject": "^2.0.0"
3653− },
3654− "dependencies": {
3655− "isobject": {
3656− "version": "2.1.0",
3657− "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
3658− "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
3659− "dev": true,
3660− "requires": {
3661− "isarray": "1.0.0"
3662− }
3663− }
3664− }
3665− },
3666− "has-values": {
3667− "version": "0.1.4",
3668− "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
3669− "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
3670− "dev": true
3671− },
3672− "isobject": {
3673− "version": "3.0.1",
3674− "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
3675− "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
3676− "dev": true
3677− }
3678− }
3679− },
3680− "unzip-response": {
3681− "version": "2.0.1",
3682− "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
3683− "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=",
3684− "dev": true
3685− },
36861475 "update-notifier": {
3687− "version": "2.5.0",
3688− "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz",
3689− "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==",
1476+ "version": "3.0.1",
1477+ "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz",
1478+ "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==",
36901479 "dev": true,
36911480 "requires": {
3692− "boxen": "^1.2.1",
1481+ "boxen": "^3.0.0",
36931482 "chalk": "^2.0.1",
3694− "configstore": "^3.0.0",
1483+ "configstore": "^4.0.0",
1484+ "has-yarn": "^2.1.0",
36951485 "import-lazy": "^2.1.0",
3696− "is-ci": "^1.0.10",
1486+ "is-ci": "^2.0.0",
36971487 "is-installed-globally": "^0.1.0",
3698− "is-npm": "^1.0.0",
3699− "latest-version": "^3.0.0",
1488+ "is-npm": "^3.0.0",
1489+ "is-yarn-global": "^0.3.0",
1490+ "latest-version": "^5.0.0",
37001491 "semver-diff": "^2.0.0",
37011492 "xdg-basedir": "^3.0.0"
3702− },
3703− "dependencies": {
3704− "ansi-styles": {
3705− "version": "3.2.1",
3706− "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
3707− "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
3708− "dev": true,
3709− "requires": {
3710− "color-convert": "^1.9.0"
3711− }
3712− },
3713− "chalk": {
3714− "version": "2.4.2",
3715− "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
3716− "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
3717− "dev": true,
3718− "requires": {
3719− "ansi-styles": "^3.2.1",
3720− "escape-string-regexp": "^1.0.5",
3721− "supports-color": "^5.3.0"
3722− }
3723− },
3724− "supports-color": {
3725− "version": "5.5.0",
3726− "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
3727− "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
3728− "dev": true,
3729− "requires": {
3730− "has-flag": "^3.0.0"
3731− }
3732− }
37331493 }
37341494 },
3735− "urix": {
3736− "version": "0.1.0",
3737− "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
3738− "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
3739− "dev": true
3740− },
37411495 "url-parse-lax": {
3742− "version": "1.0.0",
3743− "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
3744− "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
1496+ "version": "3.0.0",
1497+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
1498+ "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
37451499 "dev": true,
37461500 "requires": {
3747− "prepend-http": "^1.0.1"
1501+ "prepend-http": "^2.0.0"
37481502 }
37491503 },
3750− "use": {
3751− "version": "3.1.1",
3752− "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
3753− "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
3754− "dev": true
3755− },
3756− "util-deprecate": {
3757− "version": "1.0.2",
3758− "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
3759− "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
3760− "dev": true
3761− },
37621504 "utils-merge": {
37631505 "version": "1.0.1",
37641506 "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
37651507 "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
37661508 "dev": true
37671509 },
3768− "validate-npm-package-license": {
3769− "version": "3.0.4",
3770− "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
3771− "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
3772− "dev": true,
3773− "requires": {
3774− "spdx-correct": "^3.0.0",
3775− "spdx-expression-parse": "^3.0.0"
3776− }
3777− },
37781510 "which": {
37791511 "version": "1.3.1",
37801512 "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
@@ -3785,9 +1517,9 @@
37851517 }
37861518 },
37871519 "which-module": {
3788− "version": "1.0.0",
3789− "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
3790− "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
1520+ "version": "2.0.0",
1521+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
1522+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
37911523 "dev": true
37921524 },
37931525 "widest-line": {
@@ -3797,40 +1529,52 @@
37971529 "dev": true,
37981530 "requires": {
37991531 "string-width": "^2.1.1"
3800− }
3801− },
3802− "wrap-ansi": {
3803− "version": "2.1.0",
3804− "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
3805− "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
3806− "dev": true,
3807− "requires": {
3808− "string-width": "^1.0.1",
3809− "strip-ansi": "^3.0.1"
38101532 },
38111533 "dependencies": {
3812− "is-fullwidth-code-point": {
3813− "version": "1.0.0",
3814− "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
3815− "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
1534+ "ansi-regex": {
1535+ "version": "3.0.0",
1536+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
1537+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
1538+ "dev": true
1539+ },
1540+ "string-width": {
1541+ "version": "2.1.1",
1542+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
1543+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
38161544 "dev": true,
38171545 "requires": {
3818− "number-is-nan": "^1.0.0"
1546+ "is-fullwidth-code-point": "^2.0.0",
1547+ "strip-ansi": "^4.0.0"
38191548 }
38201549 },
3821− "string-width": {
3822− "version": "1.0.2",
3823− "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
3824− "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
1550+ "strip-ansi": {
1551+ "version": "4.0.0",
1552+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
1553+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
38251554 "dev": true,
38261555 "requires": {
3827− "code-point-at": "^1.0.0",
3828− "is-fullwidth-code-point": "^1.0.0",
3829− "strip-ansi": "^3.0.0"
1556+ "ansi-regex": "^3.0.0"
38301557 }
38311558 }
38321559 }
38331560 },
1561+ "wrap-ansi": {
1562+ "version": "5.1.0",
1563+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
1564+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
1565+ "dev": true,
1566+ "requires": {
1567+ "ansi-styles": "^3.2.0",
1568+ "string-width": "^3.0.0",
1569+ "strip-ansi": "^5.0.0"
1570+ }
1571+ },
1572+ "wrappy": {
1573+ "version": "1.0.2",
1574+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1575+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
1576+ "dev": true
1577+ },
38341578 "write-file-atomic": {
38351579 "version": "2.4.3",
38361580 "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
@@ -3843,13 +1587,12 @@
38431587 }
38441588 },
38451589 "ws": {
3846− "version": "1.1.5",
3847− "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz",
3848− "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==",
1590+ "version": "6.2.1",
1591+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
1592+ "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
38491593 "dev": true,
38501594 "requires": {
3851− "options": ">=0.0.5",
3852− "ultron": "1.0.x"
1595+ "async-limiter": "~1.0.0"
38531596 }
38541597 },
38551598 "xdg-basedir": {
@@ -3859,15 +1602,15 @@
38591602 "dev": true
38601603 },
38611604 "y18n": {
3862− "version": "3.2.1",
3863− "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
3864− "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
1605+ "version": "4.0.0",
1606+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
1607+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
38651608 "dev": true
38661609 },
38671610 "yallist": {
3868− "version": "2.1.2",
3869− "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
3870− "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
1611+ "version": "3.1.1",
1612+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
1613+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
38711614 "dev": true
38721615 },
38731616 "yargonaut": {
@@ -3879,72 +1622,77 @@
38791622 "chalk": "^1.1.1",
38801623 "figlet": "^1.1.1",
38811624 "parent-require": "^1.0.0"
3882− }
3883− },
3884− "yargs": {
3885− "version": "7.1.0",
3886− "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
3887− "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
3888− "dev": true,
3889− "requires": {
3890− "camelcase": "^3.0.0",
3891− "cliui": "^3.2.0",
3892− "decamelize": "^1.1.1",
3893− "get-caller-file": "^1.0.1",
3894− "os-locale": "^1.4.0",
3895− "read-pkg-up": "^1.0.1",
3896− "require-directory": "^2.1.1",
3897− "require-main-filename": "^1.0.1",
3898− "set-blocking": "^2.0.0",
3899− "string-width": "^1.0.2",
3900− "which-module": "^1.0.0",
3901− "y18n": "^3.2.1",
3902− "yargs-parser": "^5.0.0"
39031625 },
39041626 "dependencies": {
3905− "camelcase": {
3906− "version": "3.0.0",
3907− "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
3908− "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
1627+ "ansi-regex": {
1628+ "version": "2.1.1",
1629+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
1630+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
1631+ "dev": true
1632+ },
1633+ "ansi-styles": {
1634+ "version": "2.2.1",
1635+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
1636+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
39091637 "dev": true
39101638 },
3911− "is-fullwidth-code-point": {
3912− "version": "1.0.0",
3913− "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
3914− "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
1639+ "chalk": {
1640+ "version": "1.1.3",
1641+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
1642+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
39151643 "dev": true,
39161644 "requires": {
3917− "number-is-nan": "^1.0.0"
1645+ "ansi-styles": "^2.2.1",
1646+ "escape-string-regexp": "^1.0.2",
1647+ "has-ansi": "^2.0.0",
1648+ "strip-ansi": "^3.0.0",
1649+ "supports-color": "^2.0.0"
39181650 }
39191651 },
3920− "string-width": {
3921− "version": "1.0.2",
3922− "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
3923− "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
1652+ "strip-ansi": {
1653+ "version": "3.0.1",
1654+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
1655+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
39241656 "dev": true,
39251657 "requires": {
3926− "code-point-at": "^1.0.0",
3927− "is-fullwidth-code-point": "^1.0.0",
3928− "strip-ansi": "^3.0.0"
1658+ "ansi-regex": "^2.0.0"
39291659 }
1660+ },
1661+ "supports-color": {
1662+ "version": "2.0.0",
1663+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
1664+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
1665+ "dev": true
39301666 }
39311667 }
39321668 },
1669+ "yargs": {
1670+ "version": "14.2.3",
1671+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz",
1672+ "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
1673+ "dev": true,
1674+ "requires": {
1675+ "cliui": "^5.0.0",
1676+ "decamelize": "^1.2.0",
1677+ "find-up": "^3.0.0",
1678+ "get-caller-file": "^2.0.1",
1679+ "require-directory": "^2.1.1",
1680+ "require-main-filename": "^2.0.0",
1681+ "set-blocking": "^2.0.0",
1682+ "string-width": "^3.0.0",
1683+ "which-module": "^2.0.0",
1684+ "y18n": "^4.0.0",
1685+ "yargs-parser": "^15.0.1"
1686+ }
1687+ },
39331688 "yargs-parser": {
3934− "version": "5.0.0",
3935− "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
3936− "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
1689+ "version": "15.0.1",
1690+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz",
1691+ "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
39371692 "dev": true,
39381693 "requires": {
3939− "camelcase": "^3.0.0"
3940− },
3941− "dependencies": {
3942− "camelcase": {
3943− "version": "3.0.0",
3944− "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
3945− "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
3946− "dev": true
3947− }
1694+ "camelcase": "^5.0.0",
1695+ "decamelize": "^1.2.0"
39481696 }
39491697 }
39501698 }
package.json+1−1
@@ -9,7 +9,7 @@
99 },
1010 "dependencies": {},
1111 "devDependencies": {
12− "docsify-cli": "^4.3.0"
12+ "docsify-cli": "^4.4.0"
1313 },
1414 "scripts": {
1515 "test": "pulp test",
packages.dhall+2−1
@@ -1,5 +1,6 @@
11let upstream =
2− https://github.com/purescript/package-sets/releases/download/psc-0.13.3-20191005/packages.dhall sha256:ba287d858ada09c4164792ad4e643013b742c208cbedf5de2e35ee27b64b6817
2+ https://github.com/purescript/package-sets/releases/download/psc-0.15.9-20230629/packages.dhall
3+ sha256:f91d36c7e4793fe4d7e042c57fef362ff3f9e9ba88454cd38686701e30bf545a
34
45let overrides = {=}
56
spago.dhall+40−20
@@ -2,25 +2,45 @@
22Welcome to a Spago project!
33You can edit this file as you like.
44-}
5−{ name =
6− "purescript-graphql"
5+{ name = "purescript-graphql"
76, dependencies =
8− [ "argonaut-codecs"
9− , "argonaut-core"
10− , "console"
11− , "effect"
12− , "enums"
13− , "foldable-traversable"
14− , "nullable"
15− , "numbers"
16− , "prelude"
17− , "psci-support"
18− , "record"
19− , "spec"
20− , "string-parsers"
21− ]
22−, packages =
23− ./packages.dhall
24−, sources =
25− [ "src/**/*.purs", "test/**/*.purs" ]
7+ [ "aff"
8+ , "argonaut"
9+ , "argonaut-codecs"
10+ , "argonaut-core"
11+ , "arrays"
12+ , "bifunctors"
13+ , "console"
14+ , "control"
15+ , "datetime"
16+ , "debug"
17+ , "effect"
18+ , "either"
19+ , "enums"
20+ , "exceptions"
21+ , "foldable-traversable"
22+ , "foreign-object"
23+ , "functors"
24+ , "integers"
25+ , "lists"
26+ , "maybe"
27+ , "newtype"
28+ , "now"
29+ , "numbers"
30+ , "ordered-collections"
31+ , "parallel"
32+ , "prelude"
33+ , "psci-support"
34+ , "record"
35+ , "spec"
36+ , "string-parsers"
37+ , "strings"
38+ , "transformers"
39+ , "tuples"
40+ , "typelevel-prelude"
41+ , "unsafe-coerce"
42+ , "variant"
43+ ]
44+, packages = ./packages.dhall
45+, sources = [ "src/**/*.purs", "test/**/*.purs" ]
2646}
src/GraphQL.purs+49−9
@@ -1,17 +1,57 @@
1−module GraphQL where
1+module GraphQL
2+ ( graphql
3+ , module Execution
4+ , module Language
5+ , module GQL
6+ , module DSL
7+ , module Scalar
8+ ) where
29
310import Prelude
411
512import Control.Monad.Error.Class (class MonadError, throwError)
613import Data.Argonaut.Core (Json)
714import Data.Either (Either(..))
8−import Data.Map (empty)
15+import Data.List (mapMaybe)
16+import Data.Map (Map, fromFoldable)
17+import Data.Maybe (Maybe(..))
18+import Data.Tuple (Tuple(..))
919import Effect.Exception (Error, error)
10−import GraphQL.Execution (execute)
11−import GraphQL.Language (parse)
12−import GraphQL.Type (Schema)
20+import GraphQL.Builtin.Scalar (boolean, float, id, int, string) as Scalar
21+import GraphQL.DSL (class ArgsDefToArgsParam, class ArgsFromRows, class WithDescription, class UnionDefinition, class UnionIntrospection, class UnionResolver, arg, argsFromDefinition, argsFromRows, withDescription, enumType, field, inputField, optionalInputField, inputObjectType, listField, nullableField, nullableListField, objectType, optionalArg, union, unionIntrospection, unionResolver, withArgument, withDefaultValue, withField, withInputField, withMappingResolver, withResolver, withSimpleResolver, (!!>), (!#>), (!>), (.>), (:>), (:?>), (?>)) as DSL
22+import GraphQL.Execution (execute) as Execution
23+import GraphQL.Language (parse) as Language
24+import GraphQL.Language.AST as AST
25+import GraphQL.OptionallyParallel (class OptionallyParallel)
26+import GraphQL.Type (class GraphQLType, class InputType, class OutputType, Argument, EnumType, ExecutionContext, Field, InputField(..), InputObjectType(..), ObjectType, ScalarType(..), Schema(..), UnionType, input, introspect, output) as GQL
1327
14−graphql :: ∀ m a. MonadError Error m => Schema m a -> String -> m a -> m Json
15−graphql schema query root = case parse query of
16− Left message -> throwError $ error message
17− Right document -> execute document schema empty root
28+-- | Parses a GraphQL query string into a document and then executes the query given the parameters
29+-- |
30+-- | Parameters:
31+-- | - *schema*: the schema the query is evaluated against
32+-- | - *query*: the GraphQL query string
33+-- | - *variables*: a map of variables with their corresponding JSON values
34+-- | - *operation*: an optional operation name - can be omitted if query contains only one operation
35+-- | - *root*: a root value to be passed to the query and mutation resolvers
36+-- |
37+-- | @see https://spec.graphql.org/June2018/#sec-Execution
38+graphql ::
39+ ∀ m a f.
40+ MonadError Error m =>
41+ OptionallyParallel f m =>
42+ GQL.Schema m a ->
43+ String ->
44+ Map String Json ->
45+ Maybe String ->
46+ a ->
47+ m Json
48+graphql schema query variables operation root =
49+ case Language.parse query of
50+ Left message -> throwError $ error $ "Parsing Error: " <> message
51+ Right document@(AST.DocumentNode { definitions }) ->
52+ let
53+ fragments = fromFoldable $ definitions # mapMaybe \def -> case def of
54+ f@(AST.FragmentDefinitionNode { name: AST.NameNode n }) -> pure $ Tuple n.value f
55+ _ -> Nothing
56+ in
57+ Execution.execute document schema { variables, fragments } operation (pure root)
src/GraphQL/Builtin/Introspection.pursnew file+175
@@ -0,0 +1,175 @@
1+module GraphQL.Builtin.Introspection where
2+
3+import Prelude
4+
5+import Control.Lazy (defer)
6+import Control.Monad.Error.Class (class MonadError)
7+import Data.Array (fromFoldable)
8+import Data.Maybe (Maybe(..), isJust)
9+import Data.Newtype (unwrap)
10+import Effect.Exception (Error)
11+import GraphQL.Builtin.Scalar as Scalar
12+import GraphQL.DSL ((!#>), (.>), (:>))
13+import GraphQL.DSL (enumType, field, listField, nullableField, nullableListField, objectType) as GraphQL
14+import GraphQL.OptionallyParallel (class OptionallyParallel)
15+import GraphQL.Type (ObjectType, EnumType) as GraphQL
16+import GraphQL.Type.Introspection.Datatypes (EnumValueIntrospection, FieldIntrospection, InputValueIntrospection, SchemaIntrospection, TypeIntrospection(..), TypeKind, getDescription, getName, getTypeKind)
17+import GraphQL.Type.Introspection.Util (collectTypes)
18+
19+
20+schemaType :: forall f m. (MonadError Error m) => (OptionallyParallel f m) => GraphQL.ObjectType m SchemaIntrospection
21+schemaType = GraphQL.objectType "__Schema"
22+ :> """
23+ A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available
24+ types and directives on the server, as well as the entry points for query, mutation, and
25+ subscription operations.
26+ """
27+ .> GraphQL.listField "types" (typeType :: GraphQL.ObjectType m TypeIntrospection)
28+ :> "A list of all types supported by this server."
29+ !#> collectTypes >>> fromFoldable
30+ .> GraphQL.field "queryType" (typeType :: GraphQL.ObjectType m TypeIntrospection)
31+ :> "The type that query operations will be rooted at."
32+ !#> unwrap >>> _.queryType
33+ .> GraphQL.nullableField "mutationType" (typeType :: GraphQL.ObjectType m TypeIntrospection)
34+ :> """
35+ If this server supports mutation, the type that mutation operations will be rooted at.
36+ """
37+ !#> unwrap >>> _.mutationType
38+ .> GraphQL.nullableField "subscriptionType" (typeType :: GraphQL.ObjectType m TypeIntrospection)
39+ :> """
40+ If this server supports subscriptons, the type that subscription operations will be rooted
41+ at.
42+ """
43+ !#> const Nothing
44+ .> GraphQL.listField "directives" Scalar.string
45+ !#> const []
46+
47+
48+typeType :: forall f m. (MonadError Error m) => (OptionallyParallel f m) => GraphQL.ObjectType m TypeIntrospection
49+typeType = typeType'
50+ where
51+ typeType' = GraphQL.objectType "__Type"
52+ :> """
53+ The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in
54+ GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain
55+ fields describe information about that type. Scalar types provide no information beyond a
56+ name and description, while Enum types provide their values. Object and Interface types
57+ provide the fields they describe. Abstract types, Union and Interface, provide the Object
58+ types possible at runtime. List and NonNull types compose other types.
59+ """
60+ .> GraphQL.field "kind" typeKindType
61+ !#> getTypeKind
62+ .> GraphQL.nullableField "name" Scalar.string
63+ !#> getName
64+ .> GraphQL.nullableField "description" Scalar.string
65+ !#> getDescription
66+ .> GraphQL.nullableListField "fields" (defer \_ -> fieldType)
67+ !#> case _ of
68+ (ObjectTypeIntrospection { fields }) -> Just fields
69+ _ -> Nothing
70+ -- For spec compliance; this implementation does not support interfaces yet
71+ .> GraphQL.nullableListField "interfaces" (defer \_ -> typeType')
72+ !#> case _ of
73+ (ObjectTypeIntrospection _) -> Just []
74+ _ -> Nothing
75+ .> GraphQL.nullableListField
76+ "possibleTypes"
77+ (defer \_ -> typeType')
78+ !#> case _ of
79+ (UnionTypeIntrospection { possibleTypes }) -> Just $ possibleTypes unit
80+ _ -> Nothing
81+ .> GraphQL.nullableListField "enumValues" enumValueType
82+ !#> case _ of
83+ (EnumTypeIntrospection { enumValues }) -> Just enumValues
84+ _ -> Nothing
85+ .> GraphQL.nullableListField "inputFields" (defer \_ -> inputValueType)
86+ !#> case _ of
87+ (InputObjectTypeIntrospection { inputFields }) -> Just inputFields
88+ _ -> Nothing
89+ .> GraphQL.nullableField "ofType" (defer \_ -> typeType')
90+ !#> case _ of
91+ (ListTypeIntrospection { ofType }) -> Just (ofType unit)
92+ (NonNullTypeIntrospection { ofType }) -> Just (ofType unit)
93+ _ -> Nothing
94+
95+ typeKindType :: GraphQL.EnumType TypeKind
96+ typeKindType = GraphQL.enumType "__TypeKind"
97+ :> "An enum describing what kind of type a given `__Type` is."
98+
99+ fieldType :: GraphQL.ObjectType m FieldIntrospection
100+ fieldType = GraphQL.objectType "__Field"
101+ :> """
102+ Object and Interface types are described by a list of Fields, each of which has a name,
103+ potentially a list of arguments, and a return type.
104+ """
105+ .> GraphQL.field "name" Scalar.string
106+ !#> unwrap >>> _.name
107+ .> GraphQL.nullableField "description" Scalar.string
108+ !#> unwrap >>> _.description
109+ .> GraphQL.field "type" (defer \_ -> typeType')
110+ !#> unwrap >>> _.type >>> (_ $ unit)
111+ .> GraphQL.listField "args" (defer \_ -> inputValueType)
112+ !#> unwrap >>> _.args
113+ .> GraphQL.field "isDeprecated" Scalar.boolean
114+ !#> unwrap >>> _.deprecationReason >>> isJust
115+ .> GraphQL.nullableField "deprecationReason" Scalar.string
116+ !#> unwrap >>> _.deprecationReason
117+
118+ enumValueType :: GraphQL.ObjectType m EnumValueIntrospection
119+ enumValueType = GraphQL.objectType "__EnumValue"
120+ :> """
121+ One possible value for a given Enum. Enum values are unique values, not a placeholder for a
122+ string or numeric value. However an Enum value is returned in a JSON response as a string.
123+ """
124+ .> GraphQL.field "name" Scalar.string
125+ !#> unwrap >>> _.name
126+ .> GraphQL.nullableField "description" Scalar.string
127+ !#> unwrap >>> _.description
128+ .> GraphQL.field "isDeprecated" Scalar.boolean
129+ !#> unwrap >>> _.deprecationReason >>> isJust
130+ .> GraphQL.nullableField "deprecationReason" Scalar.string
131+ !#> unwrap >>> _.deprecationReason
132+
133+ inputValueType :: GraphQL.ObjectType m InputValueIntrospection
134+ inputValueType = GraphQL.objectType "__InputValue"
135+ :> """
136+ Arguments provided to Fields or Directives and the input fields of an InputObject are
137+ represented as Input Values which describe their type and optionally a default value.
138+ """
139+ .> GraphQL.field "name" Scalar.string
140+ !#> unwrap >>> _.name
141+ .> GraphQL.nullableField "description" Scalar.string
142+ !#> unwrap >>> _.description
143+ .> GraphQL.field "type" (defer \_ -> typeType')
144+ !#> unwrap >>> _.type >>> (_ $ unit)
145+ .> GraphQL.nullableField "defaultValue" Scalar.string
146+ !#> unwrap >>> _.defaultValue
147+
148+
149+-- type __Directive {
150+-- name: String!
151+-- description: String
152+-- locations: [__DirectiveLocation!]!
153+-- args: [__InputValue!]!
154+-- }
155+
156+-- enum __DirectiveLocation {
157+-- QUERY
158+-- MUTATION
159+-- SUBSCRIPTION
160+-- FIELD
161+-- FRAGMENT_DEFINITION
162+-- FRAGMENT_SPREAD
163+-- INLINE_FRAGMENT
164+-- SCHEMA
165+-- SCALAR
166+-- OBJECT
167+-- FIELD_DEFINITION
168+-- ARGUMENT_DEFINITION
169+-- INTERFACE
170+-- UNION
171+-- ENUM
172+-- ENUM_VALUE
173+-- INPUT_OBJECT
174+-- INPUT_FIELD_DEFINITION
175+-- }
src/GraphQL/Type/Scalar.purs → src/GraphQL/Builtin/Scalar.pursrenamed+1−1
@@ -1,4 +1,4 @@
1−module GraphQL.Type.Scalar where
1+module GraphQL.Builtin.Scalar where
22
33import Prelude
44
src/GraphQL/DSL.pursnew file+864
@@ -0,0 +1,864 @@
1+module GraphQL.DSL where
2+
3+import Prelude
4+
5+import Control.Monad.Error.Class (class MonadError, throwError)
6+import Data.Argonaut as Json
7+import Data.Array as Array
8+import Data.Bifunctor (lmap)
9+import Data.Either (Either(..), note)
10+import Data.Enum (class Enum, enumFromTo)
11+import Data.List (List, fromFoldable, find)
12+import Data.Map (empty, insert, lookup)
13+import Data.Maybe (Maybe(..), fromMaybe, maybe)
14+import Data.Newtype (unwrap)
15+import Data.String.CodeUnits (slice)
16+import Data.Symbol (class IsSymbol, reflectSymbol)
17+import Data.Traversable (class Traversable, traverse)
18+import Data.Tuple (Tuple(..))
19+import Data.Variant as Variant
20+import Effect.Exception (Error, error)
21+import GraphQL.Execution.Result (Result(..))
22+import GraphQL.Language.AST as AST
23+import GraphQL.OptionallyParallel (class OptionallyParallel)
24+import GraphQL.Type.Class (class InputType, class OutputType, ExecutionContext, input, introspect, output, showDefaultValue)
25+import GraphQL.Type.EnumType (EnumType(..), EnumValue(..))
26+import GraphQL.Type.InputObjectType (InputField(..), InputObjectType(..))
27+import GraphQL.Type.Introspection.Datatypes as IntrospectionTypes
28+import GraphQL.Type.ObjectType (Argument(..), ExecutableField(..), Field(..), ObjectType(..))
29+import GraphQL.Type.UnionType (UnionType(..), filterSelectionSet)
30+import Record as Record
31+import Type.Proxy (Proxy(..))
32+import Type.Row as Row
33+import Type.RowList as RL
34+import Unsafe.Coerce (unsafeCoerce)
35+
36+
37+-- | Creates an empty object type with the given name. Fields can be added to the object type using
38+-- | the `:>` operator from this module and the `field` functions. Object types should have at least
39+-- | one field to confirm to the GraphQL specification.
40+-- |
41+-- | *Example:*
42+-- | ```purescript
43+-- | queryType :: ObjectType Unit
44+-- | queryType = objectType "Query"
45+-- | ```
46+objectType :: forall m a. String -> ObjectType m a
47+objectType name =
48+ let
49+ introspection = IntrospectionTypes.ObjectTypeIntrospection
50+ { name, description: Nothing, fields: [] }
51+ in
52+ ObjectType (\_ -> { name, fields: empty, introspection })
53+
54+
55+-- | Create a new field for an object type. This function is typically used together with the
56+-- | `:>` operator that automatically converts the field into an executable field.
57+field :: forall m t a. OutputType m t => MonadError Error m => String -> t a -> Field m a () ()
58+field name t =
59+ Field
60+ { name
61+ , description: Nothing
62+ , args: {}
63+ , serialize
64+ , argumentIntrospections: []
65+ , typeIntrospection }
66+ where
67+ serialize (AST.FieldNode node) execCtx _ val = output t node.selectionSet execCtx (pure val)
68+ serialize _ _ _ _ = pure $ ResultError "Obtained non FieldNode for field serialisation."
69+
70+ typeIntrospection _ =
71+ IntrospectionTypes.NonNullTypeIntrospection { ofType: \_ -> introspect t }
72+
73+
74+-- | Create a new field for an object type that is a list. You can return any `Traversable` from the
75+-- | resolver.
76+listField :: forall m f t a.
77+ MonadError Error m =>
78+ Traversable f =>
79+ OutputType m t =>
80+ String ->
81+ t a ->
82+ Field m (f a) () ()
83+listField name t =
84+ Field
85+ { name
86+ , description: Nothing
87+ , args: {}
88+ , serialize
89+ , argumentIntrospections: []
90+ , typeIntrospection }
91+ where
92+ serialize (AST.FieldNode node) execCtx _ vals = do
93+ ResultList <$> fromFoldable <$> traverse (output t node.selectionSet execCtx) (pure <$> vals)
94+
95+ serialize _ _ _ _ =
96+ pure $ ResultError "Obtained non FieldNode for field serialisation."
97+
98+ typeIntrospection _ =
99+ IntrospectionTypes.NonNullTypeIntrospection
100+ { ofType: \_ ->
101+ IntrospectionTypes.ListTypeIntrospection { ofType: \_ -> introspect t }
102+ }
103+
104+
105+-- | Create a new field for an object type that is optional (i.e. it can be null). The resolver
106+-- | must now return a `Maybe`.
107+nullableField :: forall m t a.
108+ MonadError Error m =>
109+ OutputType m t =>
110+ String ->
111+ t a ->
112+ Field m (Maybe a) () ()
113+nullableField name t =
114+ Field
115+ { name
116+ , description: Nothing
117+ , args: {}
118+ , serialize
119+ , argumentIntrospections: []
120+ , typeIntrospection }
121+ where
122+ serialize (AST.FieldNode node) execCtx _ value = do
123+ case value of
124+ Nothing ->
125+ pure $ ResultNullable Nothing
126+
127+ Just val ->
128+ ResultNullable <$> Just <$> output t node.selectionSet execCtx (pure val)
129+
130+ serialize _ _ _ _ =
131+ pure $ ResultError "Obtained non FieldNode for field serialisation."
132+
133+ typeIntrospection _ = introspect t
134+
135+
136+-- | Create a new field for an object type that is optional (i.e. it can be null) and returns a
137+-- | list. The resolver must now return a `Maybe`.
138+nullableListField :: forall m f t a.
139+ MonadError Error m =>
140+ Traversable f =>
141+ OutputType m t =>
142+ String ->
143+ t a ->
144+ Field m (Maybe (f a)) () ()
145+nullableListField name t =
146+ Field
147+ { name
148+ , description: Nothing
149+ , args: {}
150+ , serialize
151+ , argumentIntrospections: []
152+ , typeIntrospection }
153+ where
154+ serialize (AST.FieldNode node) variables _ values = do
155+ case values of
156+ Nothing ->
157+ pure $ ResultNullable Nothing
158+
159+ Just vals ->
160+ ResultNullable <$>
161+ Just <$>
162+ ResultList <$>
163+ fromFoldable <$>
164+ traverse (output t node.selectionSet variables) (pure <$> vals)
165+ serialize _ _ _ _ =
166+ pure $ ResultError "Obtained non FieldNode for field serialisation."
167+
168+ typeIntrospection _ =
169+ IntrospectionTypes.ListTypeIntrospection { ofType: \_ -> introspect t }
170+
171+
172+-- | Create a tuple with a given name and a plain argument of the given type. Arguments are passed
173+-- | into the resolver. Arguments created with this function are required and the query fails if
174+-- | no value or a `null` value is supplied for this argument. To make an argument optional use
175+-- | `optionalArg` instead.
176+-- | The name argument tuple can then be used to be added to a field using the `?>` operator.
177+-- |
178+-- | *Example:*
179+-- | ```purescript
180+-- | objectType "Query"
181+-- | :> field "hello" Scalar.string
182+-- | ?> arg @"name" Scalar.string
183+-- | !> \{ name } parent -> pure $ "Hello " <> name
184+-- | ```
185+arg :: forall t a @n. InputType t => IsSymbol n => t a -> Tuple (Proxy n) (Argument a)
186+arg t =
187+ Tuple (Proxy :: _ n) $
188+ Argument
189+ { description: Nothing
190+ , resolveValue: input t
191+ , typeIntrospection: \_ -> introspect t
192+ , defaultValue: Nothing
193+ , showDefaultValue: showDefaultValue t
194+ }
195+
196+
197+-- | Provide a default value for an argument. If the argument is not supplied or the supplied value
198+-- | is `null` the default value is used instead. The default value is also returned in the
199+-- | introspection.
200+withDefaultValue :: forall n a. IsSymbol n => Tuple (Proxy n) (Argument a) -> a -> Tuple (Proxy n) (Argument a)
201+withDefaultValue (Tuple name (Argument config)) val =
202+ Tuple name $
203+ Argument
204+ { description: config.description
205+ , defaultValue: Just val
206+ , resolveValue: resolveValue
207+ , typeIntrospection: config.typeIntrospection
208+ , showDefaultValue: config.showDefaultValue
209+ }
210+
211+ where
212+ -- If there is no input given, the default value is returned instead
213+ resolveValue :: Maybe AST.ValueNode -> ExecutionContext -> Either String a
214+ resolveValue Nothing _ = pure val
215+ resolveValue node@(Just _) context = config.resolveValue node context
216+
217+
218+-- | Create a tuple with a given name and a plain argument of the given type, that is optional.
219+-- | If the argument is supplied for the field the value is available in the arguments wrapped in
220+-- | `Just`. If the argument is not supplied or the supplied value is `null` the arguments field
221+-- | in the resolver is set to `Nothing`.
222+-- | The name argument tuple can then be used to be added to a field using the `?>` operator.
223+-- |
224+-- | *Example:*
225+-- | ```purescript
226+-- | objectType "Query"
227+-- | :> field "hello" Scalar.string
228+-- | ?> optionalArg Scalar.string (Proxy :: _ "name")
229+-- | !> (\{ name } parent -> case name of
230+-- | Just n -> pure $ "Hello " <> name
231+-- | Nothing -> pure "Hello stranger"
232+-- | )
233+-- | ```
234+optionalArg ::
235+ forall t a @n.
236+ InputType t =>
237+ IsSymbol n =>
238+ t a ->
239+ Tuple (Proxy n) (Argument (Maybe a))
240+optionalArg t =
241+ Tuple (Proxy :: _ n) $
242+ Argument
243+ { description: Nothing
244+ , resolveValue
245+ , typeIntrospection: \_ -> introspect t
246+ , defaultValue: Nothing
247+ , showDefaultValue: maybe "null" (showDefaultValue t)
248+ }
249+ where
250+ -- I am not really happy with this function and it is a bit of a hack:
251+ -- We are basically proxying the input function and prevent it from failing if null is
252+ -- supplied as the variable value. It is easy to remove the Nothing case from the literal
253+ -- case but hard to remove the JSON null from the possible JSON values. I think this is the
254+ -- right place to implement this logic but I don't know how to remove this case completely
255+ -- from the input function.
256+ resolveValue Nothing _execCtx = Right Nothing
257+ resolveValue (Just AST.NullValueNode) _execCtx = Right Nothing
258+ resolveValue a@(Just (AST.VariableNode { name: AST.NameNode n})) execCtx = do
259+ variableValue <- note ("Unknown variable \"" <> n.value <> "\".") $
260+ lookup n.value execCtx.variables
261+ if Json.isNull variableValue then pure Nothing else Just <$> input t a execCtx
262+ resolveValue a execCtx = Just <$> input t a execCtx
263+
264+
265+inputObjectType :: String -> InputObjectType {}
266+inputObjectType name = InputObjectType \_ ->
267+ { name
268+ , description: Nothing
269+ , fieldIntrospection: []
270+ , input: \_ _ -> Right {}
271+ , showDefaultValue: \_ -> "{}"
272+ }
273+
274+
275+inputField :: forall t @l a. IsSymbol l => InputType t => t a -> InputField l a
276+inputField inputType = InputField
277+ { name: (Proxy :: _ l)
278+ , required: true
279+ , introspection:
280+ IntrospectionTypes.InputValueIntrospection
281+ { name: reflectSymbol (Proxy :: _ l)
282+ , description: Nothing
283+ , defaultValue: Nothing
284+ , type: \_ -> IntrospectionTypes.NonNullTypeIntrospection
285+ { ofType: \_ -> introspect inputType
286+ }
287+ }
288+ , input: input inputType
289+ , showDefaultValue: showDefaultValue inputType
290+ }
291+
292+
293+optionalInputField :: forall t l a.
294+ IsSymbol l =>
295+ InputType t =>
296+ t a ->
297+ Proxy l ->
298+ InputField l (Maybe a)
299+optionalInputField inputType label = InputField
300+ { name: label
301+ , required: false
302+ , introspection:
303+ IntrospectionTypes.InputValueIntrospection
304+ { name: reflectSymbol label
305+ , description: Nothing
306+ , defaultValue: Nothing
307+ , type: \_ -> introspect inputType
308+ }
309+ , input: \maybeValNode execContext ->
310+ case maybeValNode of
311+ Nothing -> Right Nothing
312+ Just AST.NullValueNode -> Right Nothing
313+ Just _ -> Just <$> input inputType maybeValNode execContext
314+ , showDefaultValue: maybe "null" (showDefaultValue inputType)
315+ }
316+
317+
318+-- | The withDescription type class is used to allow adding descriptions to various parts of a GraphQL
319+-- | schema that can have a description. The `.>` operator can be used with the GraphQL object
320+-- | type DSL to easily add descriptions in various places.
321+-- |
322+-- | *Example:*
323+-- | ```purescript
324+-- | objectType "User"
325+-- | :> "A user of the product."
326+-- | .> field "id" Scalar.id
327+-- | :> "A unique identifier for this user."
328+-- | ```
329+class WithDescription a where
330+ withDescription :: a -> String -> a
331+
332+
333+infixl 8 withDescription as :>
334+
335+
336+instance withDescriptionObjectType :: WithDescription (ObjectType m a) where
337+ withDescription (ObjectType configFn) s =
338+ ObjectType $ \_ ->
339+ let
340+ config = configFn unit
341+ updateDescription (IntrospectionTypes.ObjectTypeIntrospection introspection) =
342+ IntrospectionTypes.ObjectTypeIntrospection $
343+ introspection { description = Just s }
344+ updateDescription other = other
345+ in
346+ config { introspection = updateDescription config.introspection }
347+
348+
349+instance withDescriptionField :: WithDescription (Field m a argsd argsp) where
350+ withDescription (Field config) s = Field (config { description = Just s })
351+
352+
353+instance withDescriptionArgument :: WithDescription (Argument a) where
354+ withDescription (Argument config) s = Argument (config { description = Just s })
355+
356+
357+instance withDescriptionArgumentTuple :: WithDescription (Tuple s (Argument a)) where
358+ withDescription (Tuple p (Argument config)) s = Tuple p (Argument (config { description = Just s }))
359+
360+
361+instance withDescriptionEnumType :: WithDescription (EnumType a) where
362+ withDescription (EnumType config) s = EnumType ( config { description = Just s })
363+
364+
365+instance withDescriptionEnumValue :: WithDescription (EnumValue a) where
366+ withDescription (EnumValue config) s = EnumValue ( config { description = Just s })
367+
368+
369+instance withDescriptionInputObjectType :: WithDescription (InputObjectType a) where
370+ withDescription (InputObjectType configFn) s =
371+ InputObjectType $ \_ -> (configFn unit) { description = Just s }
372+
373+
374+instance withDescriptionInputField :: WithDescription (InputField s a) where
375+ withDescription (InputField config) s =
376+ InputField $ config { introspection = i }
377+ where
378+ { introspection: (IntrospectionTypes.InputValueIntrospection introspection)} = config
379+ i = IntrospectionTypes.InputValueIntrospection $ introspection { description = Just s }
380+
381+
382+-- | The `withField` function is used to add fields to an object type.
383+-- |
384+-- | When added to an object type the information about the field's arguments are hidden in the
385+-- | closure by being converted to the `ExecutableField` type.
386+withField :: forall m a argsd argsp.
387+ ArgsDefToArgsParam argsd argsp =>
388+ MonadError Error m =>
389+ ObjectType m a ->
390+ Field m a argsd argsp ->
391+ ObjectType m a
392+withField (ObjectType objectConfigFn) fld@(
393+ Field { name, description, typeIntrospection, argumentIntrospections }
394+) =
395+ ObjectType updated
396+ where
397+ updated _ =
398+ let
399+ objectConfig = objectConfigFn unit
400+ updatedFields = insert name (makeExecutable fld) objectConfig.fields
401+
402+ fieldIntrospection = IntrospectionTypes.FieldIntrospection
403+ { name
404+ , description
405+ , args: argumentIntrospections
406+ , type: typeIntrospection
407+ , deprecationReason: Nothing
408+ }
409+
410+ updateIntrospection (IntrospectionTypes.ObjectTypeIntrospection introspection) =
411+ IntrospectionTypes.ObjectTypeIntrospection $
412+ introspection { fields = Array.snoc introspection.fields fieldIntrospection }
413+ updateIntrospection other = other
414+
415+ updatedIntrospection = updateIntrospection objectConfig.introspection
416+ in
417+ objectConfig { fields = updatedFields, introspection = updatedIntrospection }
418+
419+ makeExecutable :: Field m a argsd argsp -> ExecutableField m a
420+ makeExecutable (Field { args, serialize: serialize' }) = ExecutableField { execute: execute' }
421+ where
422+ execute' :: a -> AST.SelectionNode -> ExecutionContext -> m Result
423+ execute' val node@(AST.FieldNode { arguments: argumentNodes }) variables =
424+ case argsFromDefinition argumentNodes variables args of
425+ Right argumentValues -> serialize' node variables argumentValues val
426+ Left err -> pure (ResultError err)
427+ execute' _ _ _ = pure (ResultError "Unexpected non field node field execution...")
428+
429+
430+-- | Operator for the `withField` function: Add a field to an object type.
431+-- |
432+-- | *Example:*
433+-- | ```purescript
434+-- | objectType "Query"
435+-- | :> field "hello" Scalar.string
436+-- | ```
437+infixl 5 withField as .>
438+
439+
440+-- | A type class that contrains the relationship between defined arguments and the _argument_
441+-- | parameter of a resolver.
442+class ArgsDefToArgsParam (argsd :: Row Type) (argsp :: Row Type)
443+ | argsd -> argsp
444+ , argsp -> argsd where
445+ argsFromDefinition ::
446+ List AST.ArgumentNode ->
447+ ExecutionContext ->
448+ Record argsd ->
449+ Either String (Record argsp)
450+
451+
452+instance argsDefToArgsParamImpl ::
453+ ( RL.RowToList argsd largsd
454+ , RL.RowToList argsp largsp
455+ , ArgsFromRows largsd largsp argsd argsp
456+ , RL.ListToRow largsd argsd
457+ , RL.ListToRow largsp argsp ) => ArgsDefToArgsParam argsd argsp where
458+ argsFromDefinition = argsFromRows (Proxy :: Proxy largsd) (Proxy :: Proxy largsp)
459+
460+
461+-- | ArgsDefToArgsParam that works on row lists for matching implementations
462+class ArgsFromRows
463+ (largsd :: RL.RowList Type)
464+ (largsp :: RL.RowList Type)
465+ (argsd :: Row Type)
466+ (argsp :: Row Type)
467+ where
468+ argsFromRows ::
469+ Proxy largsd ->
470+ Proxy largsp ->
471+ List AST.ArgumentNode ->
472+ ExecutionContext ->
473+ Record argsd ->
474+ Either String (Record argsp)
475+
476+
477+instance argsFromRowsCons ::
478+ ( Row.Cons l (Argument a) targsd argsd
479+ , Row.Cons l a targsp argsp
480+ , Row.Lacks l targsd
481+ , Row.Lacks l targsp
482+ , ArgsFromRows ltargsd ltargsp targsd targsp
483+ , IsSymbol l ) =>
484+ ArgsFromRows
485+ (RL.Cons l (Argument a) ltargsd)
486+ (RL.Cons l a ltargsp)
487+ argsd
488+ argsp
489+ where
490+ argsFromRows _argsdProxy _argspProxy nodes variables argsd =
491+ let key = Proxy :: Proxy l
492+ Argument argConfig = Record.get key argsd
493+ tailArgsDef = Record.delete key argsd :: Record targsd
494+ nameEquals (AST.ArgumentNode { name: AST.NameNode { value } }) =
495+ value == reflectSymbol key
496+ argumentNode = find nameEquals nodes
497+ -- Extract the argument value if the node can be found. If not use null value
498+ -- TODO: Implement default values where we would try to use the default value first
499+ valueNode = map (\(AST.ArgumentNode { value }) -> value) argumentNode
500+ improveInputError err = "Error when reading argument '" <> reflectSymbol key <> "': " <> err
501+ resolvedValue = lmap improveInputError $ argConfig.resolveValue valueNode variables
502+ tail =
503+ argsFromRows
504+ (Proxy :: Proxy ltargsd)
505+ (Proxy :: Proxy ltargsp)
506+ nodes
507+ variables
508+ tailArgsDef
509+ in Record.insert key <$> resolvedValue <*> tail
510+
511+else instance argsFromRowsNil :: ArgsFromRows RL.Nil RL.Nil argsd argsp where
512+ argsFromRows _ _ _ _ _ = pure $ unsafeCoerce {}
513+
514+
515+-- | The `withArgument` function adds an argument to a field. The argument can then be used in
516+-- | resolvers that are added to the field. The old resolver of the field is still valid until it is
517+-- | overwritten by `withResolver.`
518+withArgument :: forall m a arg n argsdold argsdnew argspold argspnew.
519+ IsSymbol n =>
520+ Row.Cons n (Argument arg) argsdold argsdnew =>
521+ Row.Cons n arg argspold argspnew =>
522+ Row.Lacks n argsdold =>
523+ Row.Lacks n argspold =>
524+ ArgsDefToArgsParam argsdold argspold =>
525+ ArgsDefToArgsParam argsdnew argspnew =>
526+ Field m a argsdold argspold ->
527+ Tuple (Proxy n) (Argument arg) ->
528+ Field m a argsdnew argspnew
529+withArgument (Field fieldConfig) (Tuple proxy argument) =
530+ Field $ fieldConfig { args = args', serialize = serialize', argumentIntrospections = intros' }
531+ where
532+ argConfig = unwrap argument
533+
534+ args' :: Record argsdnew
535+ args' = Record.insert proxy argument fieldConfig.args
536+
537+ serialize' ::
538+ AST.SelectionNode ->
539+ ExecutionContext ->
540+ Record argspnew ->
541+ a ->
542+ m Result
543+ serialize' node variables argsnew val =
544+ fieldConfig.serialize node variables (Record.delete proxy argsnew) val
545+
546+ intros' :: Array IntrospectionTypes.InputValueIntrospection
547+ intros' = Array.snoc fieldConfig.argumentIntrospections
548+ (
549+ IntrospectionTypes.InputValueIntrospection
550+ { name: reflectSymbol proxy
551+ , description: argConfig.description
552+ , type: argConfig.typeIntrospection
553+ , defaultValue: map argConfig.showDefaultValue argConfig.defaultValue
554+ }
555+ )
556+
557+
558+-- | Adds an argument to a field that can be used in the resolver.
559+-- |
560+-- | *Example:*
561+-- | ```purescript
562+-- | objectType "Query"
563+-- | :> field "hello" Scalar.string
564+-- | ?> arg (Proxy :: Proxy "name") Scalar.string
565+-- | !> (\{ name } parent -> "Hello " <> name <> "!")
566+-- | ```
567+infixl 7 withArgument as ?>
568+
569+
570+-- | The `withResolver` function adds a resolver to a field.
571+-- |
572+-- | _Note: When used multiple times on a field the resolvers are chained._
573+withResolver :: forall m a b argsd argsp.
574+ MonadError Error m =>
575+ Field m a argsd argsp ->
576+ (Record argsp -> b -> m a) ->
577+ Field m b argsd argsp
578+withResolver (Field fieldConfig) resolver =
579+ Field $ fieldConfig { serialize = serialize }
580+ where
581+ serialize :: AST.SelectionNode -> ExecutionContext -> Record argsp -> b -> m Result
582+ serialize node variables args = resolver args >=> fieldConfig.serialize node variables args
583+
584+
585+-- | Add a resolver to a field that receives the arguments in a record and the parent value.
586+-- |
587+-- | *Example:*
588+-- | ```purescript
589+-- | objectType "User"
590+-- | :> field "friends" Scalar.string
591+-- | !> (\_ user -> user >>= loadUserFriends)
592+-- | ```
593+infixl 6 withResolver as !>
594+
595+
596+-- | Add a resolver to a field that does not take the arguments. This is useful in the very common
597+-- | case that your field has no arguments.
598+withSimpleResolver :: forall m a b.
599+ MonadError Error m =>
600+ Field m a () () ->
601+ (b -> m a) ->
602+ Field m b () ()
603+withSimpleResolver fld resolver = withResolver fld (const resolver)
604+
605+
606+-- | Add a resolver to a field that receives only the parent value and ignores the arguments.
607+-- |
608+-- | *Example:*
609+-- | ```purescript
610+-- | objectType "User"
611+-- | :> field "friends" Scalar.string
612+-- | !!> (\user -> user >>= loadUserFriends)
613+-- | ```
614+infixl 6 withSimpleResolver as !!>
615+
616+
617+-- | Add a resolver that simply maps over the parent value. This is useful when you have a pure
618+-- | resolver that does not run effects.
619+withMappingResolver :: forall m a b.
620+ MonadError Error m =>
621+ Field m a () () ->
622+ (b -> a) ->
623+ Field m b () ()
624+withMappingResolver fld resolver = withSimpleResolver fld (resolver >>> pure)
625+
626+
627+-- | Add a pure resolver to a field that simply maps the parent value.
628+-- |
629+-- | *Example:*
630+-- | ```purescript
631+-- | objectType "User"
632+-- | :> field "id" Scalar.string
633+-- | !#> _.id
634+-- | ```
635+infixl 6 withMappingResolver as !#>
636+
637+
638+-- | Add a field to an input object type.
639+-- | Usually this functions operator alias
640+withInputField :: forall l a r1 r2.
641+ IsSymbol l
642+ => Row.Lacks l r1
643+ => Row.Cons l a r1 r2
644+ => InputObjectType { | r1 }
645+ -> InputField l a
646+ -> InputObjectType { | r2 }
647+withInputField (InputObjectType objConfig) (InputField inputConfig) = InputObjectType (\_ ->
648+ let
649+ config = (objConfig unit)
650+ fieldLabel = (Proxy :: Proxy l)
651+ fieldName = reflectSymbol fieldLabel
652+
653+ -- This function calls the old input function recursively and then also reads the new field
654+ -- from the provided object
655+ input :: Maybe AST.ValueNode -> ExecutionContext -> Either String (Record r2)
656+ input valueNode execCtx = do
657+ recValue <- config.input valueNode execCtx
658+ -- There are two possibilities to pass in input values: Inline or as a variable
659+ case valueNode of
660+ -- if it is a variable, we have to get the fields from JSON
661+ (Just (AST.VariableNode { name: AST.NameNode n })) ->
662+ case lookup n.value execCtx.variables of
663+ Just json -> do
664+ maybeValue <- lmap Json.printJsonDecodeError $
665+ -- TODO: We should probably throw if the variable is not an object...
666+ Json.caseJsonObject (Right Nothing) (_ `Json.getFieldOptional'` fieldName) json
667+ let hackedVariables = insert "variable_hack" (fromMaybe Json.jsonNull maybeValue) empty
668+ let hackedCtx = { fragments: execCtx.fragments, variables: hackedVariables }
669+ fieldValue <-
670+ inputConfig.input
671+ (Just (AST.VariableNode { name: (AST.NameNode { value: "variable_hack" }) }))
672+ hackedCtx
673+ pure $ Record.insert fieldLabel fieldValue recValue
674+ Nothing -> Left ("Unknown variable \"" <> n.value <> "\".")
675+
676+ -- else we have to get the values from the node
677+ (Just (AST.ObjectValueNode { fields })) ->
678+ -- here we can simply search through all the fields and try to find our value
679+ case find (\(AST.ObjectFieldNode { name: AST.NameNode n }) -> n.value == fieldName) fields of
680+ Just (AST.ObjectFieldNode { value }) -> do
681+ fieldValue <- inputConfig.input (Just value) execCtx
682+ pure $ Record.insert fieldLabel fieldValue recValue
683+ Nothing ->
684+ if inputConfig.required
685+ then Left ("Field '" <> fieldName <> "' is required in object type.")
686+ else do
687+ fieldValue <- inputConfig.input Nothing execCtx
688+ pure $ Record.insert fieldLabel fieldValue recValue
689+
690+ _ -> Left "Must provide value for required input object value."
691+
692+ fieldIntrospection = Array.cons inputConfig.introspection config.fieldIntrospection
693+
694+ showDefaultValue' :: { | r2 } -> String
695+ showDefaultValue' defaultValue =
696+ let
697+ fieldDefaultValue = Record.get fieldLabel defaultValue
698+ fieldDefaultValueString = inputConfig.showDefaultValue fieldDefaultValue
699+ existingValue = config.showDefaultValue $ Record.delete fieldLabel defaultValue
700+ keyValueString = fieldName <> ": " <> fieldDefaultValueString
701+ in
702+ case slice 0 (-1) existingValue of
703+ "{" -> "{" <> keyValueString <> "}"
704+ other -> other <> ", " <> keyValueString <> "}"
705+
706+ in config { input = input, fieldIntrospection = fieldIntrospection, showDefaultValue = showDefaultValue' }
707+ )
708+
709+
710+-- | Add a field to an input object type.
711+-- |
712+-- | *Example:*
713+-- | ```purescript
714+-- | inputObjectType "User"
715+-- | :?> inputField "name" Scalar.string
716+-- | .> "The name of the user"
717+-- | ```
718+infixl 6 withInputField as :?>
719+
720+
721+-- | Take a bounded enum and infer an enum type from that value using it's show instance to
722+-- | represent the enum string. The show function cannot return values that are not valid GraphQL
723+-- | indentifier strings. For practical reasons this is not checked at compile time. Please refer to
724+-- | the tutorial for best practices around enum values.
725+enumType :: forall a. Bounded a => Enum a => Show a => String -> EnumType a
726+enumType name = EnumType { name, description: Nothing, values }
727+ where
728+ values = enumFromTo top bottom <#> \value ->
729+ EnumValue { name: show value, description: Nothing, value, isValue: eq value }
730+
731+
732+class UnionDefinition (defRow :: Row Type) (varRow :: Row Type) (ctx :: Type -> Type)
733+ | defRow -> varRow
734+ , varRow -> defRow where
735+ union ::
736+ String ->
737+ Record defRow ->
738+ UnionType ctx (Variant.Variant varRow)
739+
740+
741+-- This instance is only to get the row list type from the record
742+instance unionDefinitionInstance ::
743+ ( RL.RowToList defRow defRowList
744+ , RL.RowToList varRow varRowList
745+ , UnionIntrospection defRowList defRow
746+ , UnionResolver defRowList varRowList defRow varRow ctx
747+ , MonadError Error ctx
748+ , RL.ListToRow defRowList defRow
749+ , RL.ListToRow varRowList varRow ) => UnionDefinition defRow varRow ctx where
750+ union name defRecord =
751+ let
752+ typeIntrospections = unionIntrospection (Proxy :: Proxy defRowList) defRecord
753+ output selectionSetNode execCtx ctxValue = ctxValue >>=
754+ unionResolver
755+ (Proxy :: Proxy defRowList)
756+ (Proxy :: Proxy varRowList)
757+ defRecord
758+ selectionSetNode
759+ execCtx
760+ in
761+ UnionType $ \_ -> { name, description: Nothing, typeIntrospections, output }
762+
763+
764+class UnionIntrospection
765+ (defRowList :: RL.RowList Type)
766+ (defRow :: Row Type)
767+ where
768+ unionIntrospection ::
769+ Proxy defRowList ->
770+ Record defRow ->
771+ Array IntrospectionTypes.TypeIntrospection
772+
773+
774+instance unionIntrospectionCons ::
775+ ( Row.Cons l (ObjectType ctx a) defRowTail defRow
776+ , Row.Lacks l defRowTail
777+ , UnionIntrospection defRowListTail defRowTail
778+ , IsSymbol l
779+ ) =>
780+ UnionIntrospection (RL.Cons l (ObjectType ctx a) defRowListTail) defRow
781+ where
782+ unionIntrospection _ defRecord =
783+ let
784+ ObjectType configFn = Record.get (Proxy :: Proxy l) defRecord
785+ config = configFn unit
786+ in
787+ -- Recursively call function
788+ Array.cons config.introspection $
789+ unionIntrospection
790+ (Proxy :: Proxy defRowListTail)
791+ -- We will just read from this value
792+ (unsafeCoerce defRecord :: Record defRowTail)
793+
794+else instance unionIntrospectionNil :: UnionIntrospection RL.Nil defRow where
795+ unionIntrospection _ _ = []
796+
797+
798+class UnionResolver
799+ (defRowList :: RL.RowList Type)
800+ (varRowList :: RL.RowList Type)
801+ (defRow :: Row Type)
802+ (varRow :: Row Type)
803+ (ctx :: Type -> Type)
804+ where
805+ unionResolver ::
806+ Proxy defRowList ->
807+ Proxy varRowList ->
808+ Record defRow ->
809+ Maybe AST.SelectionSetNode ->
810+ ExecutionContext ->
811+ (Variant.Variant varRow) ->
812+ ctx Result
813+
814+
815+instance unionResolverCons ::
816+ ( Row.Cons l (ObjectType ctx a) defRowTail defRow
817+ , Row.Cons l a varRowTail varRow
818+ , Row.Lacks l defRowTail
819+ , Row.Lacks l varRowTail
820+ , UnionResolver defRowListTail varRowListTail defRowTail varRowTail ctx
821+ , MonadError Error ctx
822+ , OptionallyParallel f ctx
823+ , IsSymbol l
824+ ) =>
825+ UnionResolver
826+ (RL.Cons l (ObjectType ctx a) defRowListTail)
827+ (RL.Cons l a varRowListTail)
828+ defRow
829+ varRow
830+ ctx
831+ where
832+ unionResolver ::
833+ Proxy (RL.Cons l (ObjectType ctx a) defRowListTail) ->
834+ Proxy (RL.Cons l a varRowListTail) ->
835+ Record defRow ->
836+ Maybe AST.SelectionSetNode ->
837+ ExecutionContext ->
838+ (Variant.Variant varRow) ->
839+ ctx Result
840+ unionResolver _defProxy _varProxy _defRecord Nothing _execCtx =
841+ const $ throwError $ error "Missing selection set for union type"
842+ unionResolver _defProxy _varProxy defRecord (Just selection) execCtx =
843+ let
844+ objectType@(ObjectType config) = Record.get (Proxy :: Proxy l) defRecord
845+ typename = (config unit).name
846+ filteredSelection = filterSelectionSet typename selection execCtx
847+ recResolver ::
848+ (Variant.Variant varRowTail) ->
849+ ctx Result
850+ recResolver =
851+ unionResolver
852+ (Proxy :: Proxy defRowListTail)
853+ (Proxy :: Proxy varRowListTail)
854+ (unsafeCoerce defRecord :: Record defRowTail)
855+ (Just selection)
856+ execCtx
857+ in
858+ recResolver
859+ # Variant.on (Proxy :: Proxy l)
860+ (pure >>> output objectType (Just filteredSelection) execCtx)
861+
862+else instance unionResolverNil :: Functor ctx => UnionResolver RL.Nil RL.Nil defRow varRow ctx where
863+ unionResolver _ _ _ _ _ = unsafeCoerce >>> Variant.case_
864+
src/GraphQL/Execution.purs+74−16
@@ -2,23 +2,81 @@ module GraphQL.Execution (execute) where
22
33import Prelude
44
5−import Control.Monad.Error.Class (class MonadError)
6−import Data.Argonaut.Core (Json, jsonEmptyObject)
7−import Data.Argonaut.Encode ((:=), (~>))
8−import Data.List (List(..))
9−import Data.Maybe (Maybe(..))
10−import Effect.Exception (Error)
5+import Control.Monad.Error.Class (class MonadError, throwError)
6+import Data.Argonaut.Core (Json)
7+import Data.List (List(..), find)
8+import Data.Maybe (Maybe(..), fromMaybe, maybe)
9+import Effect.Exception (Error, error)
10+import GraphQL.Builtin.Introspection (schemaType, typeType)
11+import GraphQL.Builtin.Scalar as Scalar
12+import GraphQL.DSL (arg, field, nullableField, (!#>), (.>), (?>), (!>))
1113import GraphQL.Execution.Result (serializeResult)
12−import GraphQL.Language.AST (DefinitionNode(..), DocumentNode(..), OperationTypeNode(..))
13−import GraphQL.Type (Schema(..), VariableMap, output)
14+import GraphQL.Language.AST (DefinitionNode(..), DocumentNode(..), NameNode(..), OperationTypeNode(..))
15+import GraphQL.OptionallyParallel (class OptionallyParallel)
16+import GraphQL.Type (ObjectType, Schema(..), ExecutionContext, output, introspect)
17+import GraphQL.Type.Introspection.Datatypes (SchemaIntrospection(..), TypeIntrospection)
18+import GraphQL.Type.Introspection.Util (findTypeByName)
1419
15−simpleError :: forall m. Applicative m => String -> m Json
16−simpleError e = pure $ "error" := e ~> jsonEmptyObject
1720
18−execute :: forall m a. MonadError Error m => DocumentNode -> Schema m a -> VariableMap -> m a -> m Json
19−execute (DocumentNode { definitions: Cons query Nil }) (Schema s) variables root =
20− case query of
21+-- | This function is mostly used internally. If you just want to execute a GraphQL query you should
22+-- | probably use `graphql` from the `GraphQL` module.
23+-- |
24+-- | This function executes GraphQL requests and roughly implements the logic outlined here:
25+-- | https://spec.graphql.org/June2018/#sec-Executing-Requests
26+execute :: forall m a f.
27+ MonadError Error m =>
28+ OptionallyParallel f m =>
29+ DocumentNode ->
30+ Schema m a ->
31+ ExecutionContext ->
32+ Maybe String ->
33+ m a ->
34+ m Json
35+execute (DocumentNode { definitions }) (Schema s) variables operation root = do
36+ -- Find the operation with the operation name given supplied. If no operation name is supplied,
37+ -- return the only operation of the document. If multiple operations are supplied without an
38+ -- operation name, or the named operation cannot be found in the document, throw an error.
39+ definitionNode <- case operation of
40+ Just operationName ->
41+ fromMaybe
42+ (throwError $ error $ "Could not find definitions with name " <> operationName <> ".")
43+ (pure <$> find (hasOperationName operationName) definitions)
44+
45+ Nothing -> case definitions of
46+ Nil -> throwError $ error "No definitions found in document."
47+ Cons query Nil -> pure query
48+ _ -> throwError $ error "Operation name is required for queries with multiple operations."
49+
50+ executionResult <- case definitionNode of
2151 OperationDefinitionNode { operation: Query, selectionSet } ->
22− serializeResult <$> output s.query (Just selectionSet) variables root
23− _ -> simpleError "Somehow received non OperationDefinitionNode for operation execution..."
24−execute _ _ _ _ = simpleError "Can only execute documents with single query"
52+ let
53+ schemaIntrospection =
54+ SchemaIntrospection
55+ { queryType: introspect s.query
56+ , mutationType: map introspect s.mutation
57+ }
58+ metaQuery = s.query
59+ .> field "__schema" (schemaType :: ObjectType m SchemaIntrospection)
60+ !#> const schemaIntrospection
61+ .> nullableField "__type" (typeType :: ObjectType m TypeIntrospection)
62+ ?> arg @"name" Scalar.string
63+ !> ( \args _ -> pure $ findTypeByName args.name schemaIntrospection )
64+ in
65+ output metaQuery (Just selectionSet) variables root
66+
67+ OperationDefinitionNode { operation: Mutation, selectionSet } ->
68+ maybe
69+ (throwError $ error "Api does not support mutations.")
70+ (\mutation -> output mutation (Just selectionSet) variables root)
71+ s.mutation
72+
73+ -- Support for subscriptions would go here in the future.
74+ _ -> throwError $ error "Unrecognised operation."
75+
76+ pure $ serializeResult executionResult
77+
78+ where
79+ hasOperationName operationName (OperationDefinitionNode { name: Just (NameNode nameNode) }) =
80+ nameNode.value == operationName
81+
82+ hasOperationName _ _ = false
src/GraphQL/Execution/FlattenAst.pursnew file+50
@@ -0,0 +1,50 @@
1+-- | This module is a little bit of a hack and it might be replaced in the future by a real
2+-- | transformation from an AST to a normalized AST. Here we will keep the data structures exported
3+-- | from the AST module and replace fragments by inlining them with their selection set.
4+module GraphQL.Execution.FlattenAst (flattenAst) where
5+
6+import Prelude
7+
8+import Data.Foldable (find, foldl)
9+import Data.List as List
10+import Data.Map as Map
11+import Data.Maybe (Maybe(..), fromMaybe)
12+import GraphQL.Language.AST as AST
13+import GraphQL.Language.AST.Util (nameFromNameNode, selectionsFromSelectionSet)
14+
15+
16+flattenAst :: AST.DocumentNode -> AST.DocumentNode
17+flattenAst (AST.DocumentNode doc) = AST.DocumentNode $ doc { definitions = defs }
18+ where
19+ fragments = doc.definitions `flip List.mapMaybe` case _ of
20+ (AST.FragmentDefinitionNode config) -> Just config
21+ _ -> Nothing
22+
23+ fragmentsMap :: Map.Map String AST.SelectionSetNode
24+ fragmentsMap =
25+ foldl (\m c -> Map.insert (nameFromNameNode c.name) c.selectionSet m) Map.empty fragments
26+
27+ findFragment fragmentName = find (_.name >>> (_ == fragmentName)) fragments
28+
29+ replaceFragment :: AST.SelectionNode -> List.List AST.SelectionNode
30+ replaceFragment f@(AST.FieldNode _) = List.singleton f
31+ replaceFragment f@(AST.FragmentSpreadNode { name }) =
32+ fromMaybe (List.singleton f) $
33+ selectionsFromSelectionSet <$>
34+ flattenSelectionSet <$>
35+ _.selectionSet <$>
36+ findFragment name
37+ replaceFragment (AST.InlineFragmentNode { selectionSet }) =
38+ selectionsFromSelectionSet $ flattenSelectionSet selectionSet
39+
40+ flattenSelectionSet :: AST.SelectionSetNode -> AST.SelectionSetNode
41+ flattenSelectionSet (AST.SelectionSetNode set) = AST.SelectionSetNode { selections }
42+ where
43+ selections = set.selections >>= replaceFragment
44+
45+ defs = doc.definitions `flip List.mapMaybe` case _ of
46+ (AST.OperationDefinitionNode def) ->
47+ Just $ AST.OperationDefinitionNode $
48+ def { selectionSet = flattenSelectionSet def.selectionSet }
49+
50+ _ -> Nothing
src/GraphQL/Execution/Normalize.pursnew file+42
@@ -0,0 +1,42 @@
1+-- | This module is used to normalize the query AST into an Executable Syntax Tree
2+module GraphQL.Execution.Normalize where
3+
4+import Prelude
5+
6+import Data.Either (Either(..))
7+import Data.List (List(..), filter, find, mapMaybe)
8+import Data.Maybe (Maybe(..))
9+import GraphQL.Language.AST as AST
10+
11+newtype NormalizedOperationNode =
12+ NormalizedOperationNode { }
13+
14+newtype NormalizedSelectionSetNode =
15+ NormalizedSelectionSetNode { selections :: List NormalizedSelectionNode }
16+
17+data NormalizedSelectionNode
18+ = NormalizedFieldSelectionNode {}
19+
20+normaliseAst :: AST.DocumentNode -> Maybe String -> Either String NormalizedOperationNode
21+normaliseAst (AST.DocumentNode { definitions }) operationName = Left "TODO"
22+ where
23+ -- In GraphQL the document can potentially contain multiple operations.
24+ -- In this case the request needs to supply a parameter called "operationName" the defines
25+ -- which of the operations should be executed.
26+ -- See: https://graphql.github.io/graphql-spec/June2018/#sec-Executing-Requests
27+ operation = case filter selectedOperationFilter definitions of
28+ Cons op Nil -> pure op
29+ Nil -> Left "No operation provided for execution."
30+ _ -> Left "Multiple operations provided for execution."
31+
32+ selectedOperationFilter (AST.OperationDefinitionNode config) = case operationName of
33+ Nothing -> true
34+ op -> op == map (\(AST.NameNode { value }) -> value) config.name
35+ selectedOperationFilter _ = false
36+
37+ -- Collect all operations that are fragments
38+ fragments = definitions `flip mapMaybe` case _ of
39+ (AST.FragmentDefinitionNode config) -> Just config
40+ _ -> Nothing
41+
42+ findFragment fragmentName = find (_.name >>> (_ == fragmentName)) fragments
src/GraphQL/Execution/Result.purs+2−1
@@ -4,8 +4,9 @@ import Prelude
44
55import Data.Argonaut.Core (Json, fromNumber, fromString, jsonEmptyObject, jsonNull)
66import Data.Argonaut.Encode (class EncodeJson, encodeJson, (:=), (~>))
7+import Data.FunctorWithIndex (mapWithIndex)
78import Data.Int as Int
8−import Data.List (List(..), foldl, mapWithIndex, null, singleton, (:))
9+import Data.List (List(..), foldl, null, singleton, (:))
910import Data.Maybe (Maybe, maybe)
1011import Data.Tuple (Tuple(..), fst, snd)
1112
src/GraphQL/Language.purs+1−1
@@ -6,7 +6,7 @@ import Data.Bifunctor (lmap)
66import Data.Either (Either)
77import GraphQL.Language.AST (DocumentNode)
88import GraphQL.Language.Parser (document)
9−import Text.Parsing.StringParser (runParser)
9+import StringParser (runParser)
1010
1111-- | Parse a query string and return a parsed GraphQL document or an error.
1212parse :: String -> Either String DocumentNode
src/GraphQL/Language/AST.purs+2−1
@@ -1,10 +1,11 @@
11module GraphQL.Language.AST where
22
33import Prelude
4+
45import Data.Generic.Rep (class Generic)
5−import Data.Generic.Rep.Show (genericShow)
66import Data.List (List)
77import Data.Maybe (Maybe)
8+import Data.Show.Generic (genericShow)
89
910data DocumentNode
1011 = DocumentNode { definitions :: List DefinitionNode }
src/GraphQL/Language/AST/Util.pursnew file+10
@@ -0,0 +1,10 @@
1+module GraphQL.Language.AST.Util where
2+
3+import Data.List (List)
4+import GraphQL.Language.AST (NameNode(..), SelectionNode, SelectionSetNode(..))
5+
6+nameFromNameNode :: NameNode -> String
7+nameFromNameNode (NameNode node) = node.value
8+
9+selectionsFromSelectionSet :: SelectionSetNode -> List SelectionNode
10+selectionsFromSelectionSet (SelectionSetNode set) = set.selections
src/GraphQL/Language/Parser.purs+40−16
@@ -16,10 +16,10 @@ import Data.List (List(..), toUnfoldable)
1616import Data.Maybe (Maybe(..), fromMaybe)
1717import Data.String.CodeUnits (fromCharArray)
1818import GraphQL.Language.AST as AST
19−import Text.Parsing.StringParser (Parser, try, fail)
20−import Text.Parsing.StringParser.CodePoints (regex, string)
21−import Text.Parsing.StringParser.CodeUnits (char, noneOf)
22−import Text.Parsing.StringParser.Combinators (between, many, optionMaybe)
19+import StringParser (Parser, fail, try)
20+import StringParser.CodePoints (regex, string)
21+import StringParser.CodeUnits (char, noneOf)
22+import StringParser.Combinators (between, many, optionMaybe)
2323
2424parens :: forall a. Parser a -> Parser a
2525parens = between (char '(') (char ')')
@@ -42,8 +42,8 @@ name = AST.NameNode <$> {value: _} <$> regex "[_A-Za-z][_0-9A-Za-z]*"
4242-- | For performance they are all summarised in a single regex which is a bit different
4343-- | from the specification that knows different types of ignored tokens.
4444-- | See: https://graphql.github.io/graphql-spec/June2018/#sec-Source-Text.Ignored-Tokens
45−whiteSpace :: Parser String
46−whiteSpace = regex "(#[^\\n\\r]\\n\\r]|[, \\u0009\\n\\r\\uFEFF])*" -- Comments not completely correct
45+whiteSpace :: Parser Unit
46+whiteSpace = pure unit <* regex "(#[^\\n\\r]\\n\\r]|[, \\u0009\\n\\r\\uFEFF])*" -- Comments not completely correct
4747
4848-- | Helper function to parse tokens wrapped in white space
4949token :: String -> Parser String
@@ -55,10 +55,16 @@ document :: Parser AST.DocumentNode
5555document = AST.DocumentNode <<< {definitions: _} <$> many definition
5656
5757definition :: Parser AST.DefinitionNode
58−definition = do
58+definition = operationDefinition <|> fragmentDefinition
59+
60+operationDefinition :: Parser AST.DefinitionNode
61+operationDefinition = do
62+ whiteSpace
5963 header <- optionMaybe operationHeader
6064 v <- variableDefinitionList <* whiteSpace <|> pure Nil
61− s <- selectionSet <* whiteSpace
65+ s <- selectionSet
66+ whiteSpace
67+ -- If the operation has no keyword and no name it is an unnamed query
6268 let { op, n } = fromMaybe { op: AST.Query, n: Nothing } header
6369 pure $ AST.OperationDefinitionNode {name: n, operation: op, selectionSet: s, variableDefinitions: v }
6470 where
@@ -66,10 +72,24 @@ definition = do
6672 toOperation _ = AST.Mutation
6773 variableDefinitionList = parens $ many (whiteSpace *> variableDefinition <* whiteSpace)
6874 operationHeader = do
69− op <- toOperation <$> (token "query" <|> token "mutation")
70− n <- optionMaybe $ name <* whiteSpace
75+ op <- toOperation <$> (string "query" <|> string "mutation")
76+ whiteSpace
77+ n <- optionMaybe $ name
78+ whiteSpace
7179 pure { op, n }
7280
81+fragmentDefinition :: Parser AST.DefinitionNode
82+fragmentDefinition = do
83+ n <- token "fragment" *> name
84+ typeCondition <- token "on" *> simpleNamedType <* whiteSpace
85+ s <- selectionSet <* whiteSpace
86+ pure $ AST.FragmentDefinitionNode
87+ { directives: mempty
88+ , name: n
89+ , selectionSet: s
90+ , typeCondition
91+ }
92+
7393variableDefinition :: Parser AST.VariableDefinitionNode
7494variableDefinition = do
7595 n <- char '$' *> name <* token ":"
@@ -96,16 +116,20 @@ selectionSet =
96116 braces $ AST.SelectionSetNode <<< {selections: _} <$> many (defer \_ -> selection)
97117
98118selection :: Parser AST.SelectionNode
99−selection =
100− try (whiteSpace *> defer \_ -> field <* whiteSpace)
101− <|> try (whiteSpace *> fragmentSpread <* whiteSpace)
102− <|> (whiteSpace *> inlineFragment <* whiteSpace)
119+selection = between whiteSpace whiteSpace $ try (defer \_ -> field) <|> try inlineFragment <|> fragmentSpread
103120 where
104121 fragmentSpread :: Parser AST.SelectionNode
105− fragmentSpread = fail "Fragment spread not yet supported"
122+ fragmentSpread = AST.FragmentSpreadNode <<< {name: _, directives: Nil } <$> (token "..." *> name)
106123
107124 inlineFragment :: Parser AST.SelectionNode
108− inlineFragment = fail "Inline Fragments not yet supported"
125+ inlineFragment = do
126+ typeCondition <- token "..." *> token "on" *> simpleNamedType <* whiteSpace
127+ s <- selectionSet <* whiteSpace
128+ pure $ AST.InlineFragmentNode
129+ { typeCondition
130+ , directives: mempty
131+ , selectionSet: s
132+ }
109133
110134 field :: Parser AST.SelectionNode
111135 field = do
src/GraphQL/Language/Printer.pursnew file+80
@@ -0,0 +1,80 @@
1+module GraphQL.Language.Printer where
2+
3+import Prelude
4+
5+import Data.Foldable (intercalate)
6+import Data.String (Pattern(..), split)
7+import GraphQL.Language.AST as AST
8+
9+data Doc
10+ = Nil
11+ | Text String Doc
12+ | Line Int Doc
13+
14+instance semigroupDoc :: Semigroup Doc where
15+ append Nil d = d
16+ append d Nil = d
17+ append (Text s1 Nil) (Text s2 ds) = Text (s1 <> s2) ds
18+ append (Text s Nil) d = Text s d
19+ append (Text s ds) d = Text s (append ds d)
20+ append (Line i Nil) d = Line i d
21+ append (Line i ds) d = Line i (append ds d)
22+
23+instance monoidDoc :: Monoid Doc where
24+ mempty = Nil
25+
26+text :: String -> Doc
27+text str = Text str Nil
28+
29+line :: Doc
30+line = Line 0 Nil
31+
32+nest :: Int -> Doc -> Doc
33+nest indent Nil = Nil
34+nest indent (Text s ds) = Text s (nest indent ds)
35+nest indent (Line i ds) = Line (i + indent) (nest indent ds)
36+
37+layout :: Doc -> String
38+layout Nil = ""
39+layout (Text s ds) = s <> (layout ds)
40+layout (Line i ds) = "\n" <> repeat " " i <> layout ds
41+
42+repeat :: String -> Int -> String
43+repeat str times = repeatRec str times ""
44+ where
45+ repeatRec _ 0 acc = acc
46+ repeatRec s i acc = repeatRec s (i - 1) (s <> acc)
47+
48+printNameNode :: AST.NameNode -> Doc
49+printNameNode (AST.NameNode { value }) = text value
50+
51+printSimpleNamedTypeNode :: AST.SimpleNamedTypeNode -> Doc
52+printSimpleNamedTypeNode (AST.SimpleNamedTypeNode { name }) = printNameNode name
53+
54+printTypeNode :: AST.TypeNode -> Doc
55+printTypeNode (AST.NamedTypeNode { "type": t }) = printSimpleNamedTypeNode t
56+printTypeNode (AST.NonNullTypeNode { "type": t }) = printTypeNode t <> text "!"
57+printTypeNode (AST.ListTypeNode { "type": t }) = text "[" <> printTypeNode t <> text "]"
58+
59+printObjectFieldNode :: AST.ObjectFieldNode -> Doc
60+printObjectFieldNode (AST.ObjectFieldNode { name, value }) =
61+ printNameNode name <> text ": " <> printValueNode value
62+
63+printValueNode :: AST.ValueNode -> Doc
64+printValueNode (AST.VariableNode { name }) = text "$" <> printNameNode name
65+printValueNode (AST.IntValueNode { value }) = text value
66+printValueNode (AST.FloatValueNode { value }) = text value
67+printValueNode (AST.StringValueNode { value, block }) =
68+ if block then printBlockString value else text ("\"" <> value <> "\"")
69+printValueNode (AST.BooleanValueNode { value }) = if value then text "true" else text "false"
70+printValueNode AST.NullValueNode = text "null"
71+printValueNode (AST.EnumValueNode { name }) = printNameNode name
72+printValueNode (AST.ListValueNode { values }) =
73+ text "[" <> intercalate (text ", ") (map printValueNode values) <> text "]"
74+printValueNode (AST.ObjectValueNode { fields }) =
75+ text "{" <> intercalate (text ", ") (map printObjectFieldNode fields) <> text "}"
76+
77+printBlockString :: String -> Doc
78+printBlockString str =
79+ let lines = map text (split (Pattern "\n") str)
80+ in text "\"\"\"" <> line <> intercalate line lines <> line <> text "\"\"\""
src/GraphQL/OptionallyParallel.pursnew file+30
@@ -0,0 +1,30 @@
1+module GraphQL.OptionallyParallel where
2+
3+import Prelude
4+
5+import Control.Monad.Reader (ReaderT, mapReaderT)
6+import Control.Parallel (class Parallel, parallel, sequential)
7+import Data.Either (Either)
8+import Effect (Effect)
9+
10+class OptionallyParallel :: (Type -> Type) -> (Type -> Type) -> Constraint
11+class (Monad m, Applicative f) <= OptionallyParallel f m | m -> f, f -> m where
12+ optionallyParallel :: m ~> f
13+ optionallySequential :: f ~> m
14+
15+
16+instance OptionallyParallel (Either a) (Either a) where
17+ optionallyParallel = identity
18+ optionallySequential = identity
19+
20+else instance (OptionallyParallel f m) => OptionallyParallel (ReaderT a f) (ReaderT a m) where
21+ optionallyParallel = mapReaderT optionallyParallel
22+ optionallySequential = mapReaderT optionallySequential
23+
24+else instance OptionallyParallel Effect Effect where
25+ optionallyParallel = identity
26+ optionallySequential = identity
27+
28+else instance (Parallel f m) => OptionallyParallel f m where
29+ optionallyParallel = parallel
30+ optionallySequential = sequential
src/GraphQL/Type.purs+17−485
@@ -1,485 +1,17 @@
1−module GraphQL.Type where
2−
3−import Prelude
4−
5−import Control.Monad.Error.Class (class MonadError, catchError, throwError)
6−import Data.Argonaut.Core as Json
7−import Data.Either (Either(..), note)
8−import Data.Enum (class Enum, enumFromTo)
9−import Data.List (List, fromFoldable)
10−import Data.Map (Map, empty, insert, lookup)
11−import Data.Maybe (Maybe(..), fromMaybe)
12−import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
13−import Data.Traversable (class Traversable, find, traverse)
14−import Data.Tuple (Tuple(..))
15−import Effect.Exception (Error, error, message)
16−import GraphQL.Execution.Result (Result(..))
17−import GraphQL.Language.AST as AST
18−import Record as Record
19−import Type.Data.RowList (RLProxy(..))
20−import Type.Row as Row
21−import Type.RowList as RL
22−import Unsafe.Coerce (unsafeCoerce)
23−
24−-- | The schema contains the central entry points for GraphQL queries.
25−newtype Schema m a = Schema { query :: ObjectType m a }
26−
27−type VariableMap = Map String Json.Json
28−
29−-- | The input type class is used for all GraphQL types that can be used as input types.
30−class InputType t where
31− input :: forall a. t a -> Maybe AST.ValueNode -> VariableMap -> Either String a
32−
33−-- | The output type class is used for all GraphQL types that can be used as output types.
34−-- | It has instances for GraphQL types that can resolve a value within a certain monad error.
35−class MonadError Error m <= OutputType m t where
36− output :: forall a. t a -> Maybe AST.SelectionSetNode -> VariableMap -> m a -> m Result
37−
38−-- | Scalar types are the leaf nodes of a GraphQL schema. Scalar types can be serialised into JSON
39−-- | or obtained from a JSON when read from the variables provided by a query. Furthermore values
40−-- | can be read from literals in a GraphQL document. To create a scalar type a name and optionally
41−-- | a description need to be provided.
42−-- | The functions `parseLiteral`, `parseValue` and `serialize` are used to convert between the
43−-- | GraphQL transport formats and PureScript representations.
44−-- |
45−-- | The GraphQL PureScript implementation comes with the four default scalars defined in the
46−-- | specification.
47−newtype ScalarType a =
48− ScalarType
49− { name :: String
50− , description :: Maybe String
51− , parseLiteral :: AST.ValueNode -> Either String a
52− , parseValue :: Json.Json -> Either String a
53− , serialize :: a -> Json.Json
54− }
55−
56−instance inputTypeScalarType :: InputType ScalarType where
57− input (ScalarType config) (Just node) variables = case node of
58− (AST.VariableNode { name: AST.NameNode { value }}) -> do
59− json <- note ("Required variable `" <> value <> "` was not provided.") $
60− lookup value variables
61− config.parseValue json
62− _ -> config.parseLiteral node
63− input _ Nothing _ = Left "Must provide value for required scalar."
64−
65−instance outputTypeScalarType :: (MonadError Error m) => OutputType m ScalarType where
66− output (ScalarType s) Nothing _ val = ResultLeaf <$> map s.serialize val
67− output _ _ _ _ = pure $ ResultError "Invalid subselection on scalar type!"
68−
69−instance showScalarType :: Show (ScalarType a) where
70− show (ScalarType { name }) = "scalar " <> name
71−
72−newtype ObjectType m a =
73− ObjectType
74− { name :: String
75− , description :: Maybe String
76− , fields :: Map String (ExecutableField m a)
77− }
78−
79−instance outputTypeObjectType :: (MonadError Error m) => OutputType m (ObjectType m) where
80− output (ObjectType o) (Just (AST.SelectionSetNode { selections })) variables val =
81− ResultObject <$> traverse serializeField selections
82− where
83− serializeField :: AST.SelectionNode -> m (Tuple String Result)
84− serializeField node@(AST.FieldNode fld) =
85− let (AST.NameNode { value: name }) = fld.name
86− (AST.NameNode { value: alias }) = fromMaybe fld.name fld.alias
87− in case lookup name o.fields of
88− Just (ExecutableField { execute }) ->
89− Tuple alias <$>
90− (flip catchError (message >>> ResultError >>> pure) $
91− execute val node variables)
92− Nothing ->
93− if
94− name == "__typename"
95− then
96− pure $ Tuple alias $ ResultLeaf $ Json.fromString o.name
97− else
98− pure $ Tuple alias $
99− ResultError ("Unknown field `" <> name <> "` on type `" <> o.name <> "`.")
100− -- TODO: This branch needs fixing. It is for fragment spreads and so on. Maybe normalise
101− -- the query first and completely eliminate the branch...
102− serializeField _ = pure $ Tuple "unknown" $ ResultError "Unexpected fragment spread!"
103− output _ _ _ _ = pure $ ResultError "Missing subselection on object type."
104−
105−instance showObjectType :: Show (ObjectType m a) where
106− show (ObjectType { name }) = "type " <> name
107−
108−-- | The executable field loses the information about it's arguments types. This is needed to add it
109−-- | to the map of arguments of the object type. The execute function will extract the arguments of
110−-- | the field from the AST.
111−newtype ExecutableField m a =
112− ExecutableField { execute :: m a -> AST.SelectionNode -> VariableMap -> m Result }
113−
114−-- | Object types can have fields. Fields are constructed using the `field` function from this
115−-- | module and added to object types using the `:>` operator.
116−newtype Field m a argsd argsp =
117− Field
118− { name :: String
119− , description :: Maybe String
120− , args :: Record argsd
121− , serialize :: AST.SelectionNode -> VariableMap -> Record argsp -> m a -> m Result
122− }
123−
124−-- | Fields can have multiple arguments. Arguments are constructed using the `arg` function from
125−-- | this module and the `?>` operator.
126−newtype Argument a =
127− Argument
128− { description :: Maybe String
129− , resolveValue :: Maybe AST.ValueNode -> VariableMap -> Either String a
130− }
131−
132−newtype EnumType a =
133− EnumType
134− { name :: String
135− , description :: Maybe String
136− , values :: Array (EnumValue a)
137− }
138−
139−newtype EnumValue a =
140− EnumValue
141− { name :: String
142− , description :: Maybe String
143− , value :: a
144− , isValue :: a -> Boolean }
145−
146−instance inputTypeEnumType :: InputType EnumType where
147− input (EnumType config) (Just node) variables =
148− let lookupName name =
149− note ("Unknown enum value `" <> name <> "` for type `" <> config.name <> "`.") $
150− find (\(EnumValue val) -> val.name == name) config.values
151− in case node of
152− AST.VariableNode { name: AST.NameNode { value: name } } -> do
153− json <- note ("Required variable `" <> name <> "` was not provided.") $
154− lookup name variables
155− EnumValue val <- Json.caseJsonString (Left "Enum values must be strings.") lookupName json
156− pure val.value
157−
158− AST.EnumValueNode { name: AST.NameNode { value: name } } -> do
159− EnumValue val <- lookupName name
160− pure val.value
161−
162− _ -> Left "Unexpected non-enum value node for enum value."
163−
164− input _ _ _ = Left "Missing value for required argument."
165−
166−instance outputTypeEnumType :: MonadError Error m => OutputType m EnumType where
167− output :: forall a. EnumType a -> Maybe AST.SelectionSetNode -> VariableMap -> m a -> m Result
168− output (EnumType config) Nothing _ mValue = do
169− value <- mValue
170− case find (\(EnumValue { isValue }) -> isValue value) config.values of
171− Nothing ->
172− throwError $ error "Could not select enum value representation from provided value."
173−
174− Just (EnumValue val) ->
175− pure $ ResultLeaf $ Json.fromString val.name
176−
177− output _ _ _ _ = pure $ ResultError "Invalid subselection on enum type!"
178−
179−-- | Creates an empty object type with the given name. Fields can be added to the object type using
180−-- | the `:>` operator from this module.
181−objectType :: forall m a. String -> ObjectType m a
182−objectType name =
183− ObjectType { name, description: Nothing, fields: empty }
184−
185−-- | Create a new field for an object type. This function is typically used together with the
186−-- | `:>` operator that automatically converts the field into an executable field.
187−field :: forall m t a. OutputType m t => MonadError Error m => String -> t a -> Field m a () ()
188−field name t = Field { name, description: Nothing, args: {}, serialize }
189− where
190− serialize (AST.FieldNode node) variables _ val = output t node.selectionSet variables val
191− serialize _ _ _ _ = pure $ ResultError "Obtained non FieldNode for field serialisation."
192−
193−-- | Create a new field for an object type that is a list. You can return any `Foldable` in the
194−-- | resolver.
195−listField :: forall m f t a.
196− MonadError Error m =>
197− Traversable f =>
198− OutputType m t =>
199− String ->
200− t a ->
201− Field m (f a) () ()
202−listField name t = Field { name, description: Nothing, args: {}, serialize }
203− where
204− serialize (AST.FieldNode node) variables _ mVals = do
205− vals <- mVals
206− ResultList <$> fromFoldable <$> traverse (output t node.selectionSet variables) (pure <$> vals)
207−
208− serialize _ _ _ _ =
209− pure $ ResultError "Obtained non FieldNode for field serialisation."
210−
211−-- | Create a new field for an object type that is optional (i.e. it can be null). The resolver
212−-- | must now return a `Maybe`.
213−nullableField :: forall m t a.
214− MonadError Error m =>
215− OutputType m t =>
216− String ->
217− t a ->
218− Field m (Maybe a) () ()
219−nullableField name t = Field { name, description: Nothing, args: {}, serialize }
220− where
221− serialize (AST.FieldNode node) variables _ mValue = do
222− value <- mValue
223− case value of
224− Nothing ->
225− pure $ ResultNullable Nothing
226−
227− Just val ->
228− ResultNullable <$> Just <$> output t node.selectionSet variables (pure val)
229−
230− serialize _ _ _ _ =
231− pure $ ResultError "Obtained non FieldNode for field serialisation."
232−
233−-- | Create a tuple with a given name and a plain argument of the given type.
234−-- | The name argument tuple can then be used to be added to a field using the `?>` operator.
235−arg :: forall t a n. InputType t => IsSymbol n => t a -> SProxy n -> Tuple (SProxy n) (Argument a)
236−arg t name =
237− Tuple (SProxy :: _ n) $
238− Argument { description: Nothing, resolveValue: input t }
239−
240−-- * Combinator operators
241−
242−-- | The describe type class is used to allow adding descriptions to various parts of a GraphQL
243−-- | schema that can have a description. The `.>` operator can be used with the GraphQL object
244−-- | type DSL to easily add descriptions in various places.
245−-- |
246−-- | *Example:*
247−-- | ```purescript
248−-- | objectType "User"
249−-- | .> "A user of the product."
250−-- | :> "id" Scalar.id
251−-- | .> "A unique identifier for this user."
252−-- | ```
253−class Describe a where
254− describe :: a -> String -> a
255−
256−infixl 8 describe as .>
257−
258−instance describeObjectType :: Describe (ObjectType m a) where
259− describe (ObjectType config) s = ObjectType (config { description = Just s })
260−
261−instance describeField :: Describe (Field m a argsd argsp) where
262− describe (Field config) s = Field (config { description = Just s })
263−
264−instance describeArgument :: Describe (Argument a) where
265− describe (Argument config) s = Argument (config { description = Just s })
266−
267−instance describeEnumType :: Describe (EnumType a) where
268− describe (EnumType config) s = EnumType ( config { description = Just s })
269−
270−instance describeEnumValue :: Describe (EnumValue a) where
271− describe (EnumValue config) s = EnumValue ( config { description = Just s })
272−
273−-- | The `withField` function is used to add fields to an object type.
274−-- |
275−-- | When added to an object type the information about the field's argument are hidden in the
276−-- | closure by being converted to the `ExecutableField` type.
277−withField :: forall m a argsd argsp.
278− ArgsDefToArgsParam argsd argsp =>
279− MonadError Error m =>
280− ObjectType m a ->
281− Field m a argsd argsp ->
282− ObjectType m a
283−withField (ObjectType objectConfig) fld@(Field { name }) =
284− ObjectType $ objectConfig { fields = insert name (makeExecutable fld) objectConfig.fields }
285− where
286− makeExecutable :: Field m a argsd argsp -> ExecutableField m a
287− makeExecutable (Field { args, serialize: serialize' }) = ExecutableField { execute: execute' }
288− where
289− execute' :: m a -> AST.SelectionNode -> VariableMap -> m Result
290− execute' val node@(AST.FieldNode { arguments: argumentNodes }) variables =
291− case argsFromDefinition argumentNodes variables args of
292− Right argumentValues -> serialize' node variables argumentValues val
293− Left err -> pure (ResultError err)
294− execute' _ _ _ = pure (ResultError "Unexpected non field node field execution...")
295−
296−-- | Add a field to an object type.
297−-- |
298−-- | *Example:*
299−-- | ```purescript
300−-- | objectType "Query"
301−-- | :> field "hello" Scalar.string
302−-- | ```
303−infixl 5 withField as :>
304−
305−-- | A type class that contrains the relationship between defined arguments and the _argument_
306−-- | parameter of a resolver.
307−class ArgsDefToArgsParam (argsd :: # Type) (argsp :: # Type)
308− | argsd -> argsp
309− , argsp -> argsd where
310− argsFromDefinition ::
311− List AST.ArgumentNode ->
312− VariableMap ->
313− Record argsd ->
314− Either String (Record argsp)
315−
316−instance argsDefToArgsParamImpl ::
317− ( RL.RowToList argsd largsd
318− , RL.RowToList argsp largsp
319− , ArgsFromRows largsd largsp argsd argsp
320− , RL.ListToRow largsd argsd
321− , RL.ListToRow largsp argsp ) => ArgsDefToArgsParam argsd argsp where
322− argsFromDefinition = argsFromRows (RLProxy :: RLProxy largsd) (RLProxy :: RLProxy largsp)
323−
324−-- | ArgsDefToArgsParam that works on row lists for matching implementations
325−class ArgsFromRows
326− (largsd :: RL.RowList)
327− (largsp :: RL.RowList)
328− (argsd :: # Type)
329− (argsp :: # Type)
330− where
331− argsFromRows ::
332− RLProxy largsd ->
333− RLProxy largsp ->
334− List AST.ArgumentNode ->
335− VariableMap ->
336− Record argsd ->
337− Either String (Record argsp)
338−
339−instance argsFromRowsCons ::
340− ( Row.Cons l (Argument a) targsd argsd
341− , Row.Cons l a targsp argsp
342− , Row.Lacks l targsd
343− , Row.Lacks l targsp
344− , ArgsFromRows ltargsd ltargsp targsd targsp
345− , IsSymbol l ) =>
346− ArgsFromRows
347− (RL.Cons l (Argument a) ltargsd)
348− (RL.Cons l a ltargsp)
349− argsd
350− argsp
351− where
352− argsFromRows argsdProxy argspProxy nodes variables argsd =
353− let key = SProxy :: SProxy l
354− Argument argConfig = Record.get key argsd
355− tailArgsDef = Record.delete key argsd :: Record targsd
356− nameEquals (AST.ArgumentNode { name: AST.NameNode { value } }) =
357− value == reflectSymbol key
358− argumentNode = find nameEquals nodes
359− -- Extract the argument value if the node can be found. If not use null value
360− -- TODO: Implement default values where we would try to use the default value first
361− valueNode = map (\(AST.ArgumentNode { value }) -> value) argumentNode
362− tail =
363− argsFromRows
364− (RLProxy :: RLProxy ltargsd)
365− (RLProxy :: RLProxy ltargsp)
366− nodes
367− variables
368− tailArgsDef
369− in Record.insert key <$> (argConfig.resolveValue valueNode variables) <*> tail
370−
371−else instance argsFromRowsNil :: ArgsFromRows RL.Nil RL.Nil argsd argsp where
372− argsFromRows _ _ _ _ _ = pure $ unsafeCoerce {}
373−
374−-- | The `withArgument` function adds an argument to a field. The argument can then be used in
375−-- | resolvers that are added to the field. The old resolver of the field is still valid until it is
376−-- | overwritten by `withResolver.`
377−withArgument :: forall m a arg n argsdold argsdnew argspold argspnew.
378− IsSymbol n =>
379− Row.Cons n (Argument arg) argsdold argsdnew =>
380− Row.Cons n arg argspold argspnew =>
381− Row.Lacks n argsdold =>
382− Row.Lacks n argspold =>
383− ArgsDefToArgsParam argsdold argspold =>
384− ArgsDefToArgsParam argsdnew argspnew =>
385− Field m a argsdold argspold ->
386− Tuple (SProxy n) (Argument arg) ->
387− Field m a argsdnew argspnew
388−withArgument (Field fieldConfig) (Tuple proxy argument) =
389− Field $ fieldConfig { args = args', serialize = serialize' }
390− where
391− args' :: Record argsdnew
392− args' = Record.insert proxy argument fieldConfig.args
393−
394− serialize' ::
395− AST.SelectionNode ->
396− VariableMap ->
397− Record argspnew ->
398− m a ->
399− m Result
400− serialize' node variables argsnew val =
401− fieldConfig.serialize node variables (Record.delete proxy argsnew) val
402−
403−-- | Adds an argument to a field that can be used in the resolver.
404−-- |
405−-- | *Example:*
406−-- | ```purescript
407−-- | objectType "Query"
408−-- | :> field "hello" Scalar.string
409−-- | ?> arg (SProxy :: SProxy "name") Scalar.string
410−-- | !> (\{ name } parent -> "Hello " <> name <> "!")
411−-- | ```
412−infixl 7 withArgument as ?>
413−
414−-- | The `withResolver` function adds a resolver to a field.
415−-- |
416−-- | _Note: When used multiple times on a field the resolvers are chained._
417−withResolver :: forall m a b argsd argsp.
418− MonadError Error m =>
419− Field m a argsd argsp ->
420− (Record argsp -> m b -> m a) ->
421− Field m b argsd argsp
422−withResolver (Field fieldConfig) resolver =
423− Field $ fieldConfig { serialize = serialize }
424− where
425− serialize :: AST.SelectionNode -> VariableMap -> Record argsp -> m b -> m Result
426− serialize node variables args val =
427− fieldConfig.serialize node variables args (resolver args val)
428−
429−-- | Add a resolver to a field that receives the arguments in a record and the parent value.
430−-- |
431−-- | *Example:*
432−-- | ```purescript
433−-- | objectType "User"
434−-- | :> field "friends" Scalar.string
435−-- | !> (\_ user -> user >>= loadUserFriends)
436−-- | ```
437−infixl 6 withResolver as !>
438−
439−-- | Add a resolver to a field that does not take the arguments. This is useful in the very common
440−-- | case that your field has no arguments.
441−withSimpleResolver :: forall m a b.
442− MonadError Error m =>
443− Field m a () () ->
444− (m b -> m a) ->
445− Field m b () ()
446−withSimpleResolver fld resolver = withResolver fld (const resolver)
447−
448−-- | Add a resolver to a field that receives only the parent value and ignores the arguments.
449−-- |
450−-- | *Example:*
451−-- | ```purescript
452−-- | objectType "User"
453−-- | :> field "friends" Scalar.string
454−-- | !!> (\user -> user >>= loadUserFriends)
455−-- | ```
456−infixl 6 withSimpleResolver as !!>
457−
458−-- | Add a resolver that simply maps over the parent value. This is useful when you have a pure
459−-- | resolver that does not run effects.
460−withMappingResolver :: forall m a b.
461− MonadError Error m =>
462− Field m a () () ->
463− (b -> a) ->
464− Field m b () ()
465−withMappingResolver fld resolver = withSimpleResolver fld (map resolver)
466−
467−-- | Add a pure resolver to a field that simply maps the parent value.
468−-- |
469−-- | *Example:*
470−-- | ```purescript
471−-- | objectType "User"
472−-- | :> field "id" Scalar.string
473−-- | !#> _.id
474−-- | ```
475−infixl 6 withMappingResolver as !#>
476−
477−-- | Take a bounded enum and infer an enum type from that value using it's show instance to
478−-- | represent the enum string. The show function cannot return values that are not valid GraphQL
479−-- | indentifier strings. For practical reasons this is not checked at compile time. Please refer to
480−-- | the tutorial for best practices around enum values.
481−enumType :: forall a. Bounded a => Enum a => Show a => String -> EnumType a
482−enumType name = EnumType { name, description: Nothing, values }
483− where
484− values = enumFromTo top bottom <#> \value ->
485− EnumValue { name: show value, description: Nothing, value, isValue: eq value }
1+module GraphQL.Type
2+ ( module Schema
3+ , module Class
4+ , module ScalarType
5+ , module ObjectType
6+ , module EnumType
7+ , module UnionType
8+ , module InputObjectType
9+ ) where
10+
11+import GraphQL.Type.Schema (Schema(..)) as Schema
12+import GraphQL.Type.Class (class GraphQLType, class InputType, class OutputType, ExecutionContext, input, introspect, output) as Class
13+import GraphQL.Type.ScalarType (ScalarType(..)) as ScalarType
14+import GraphQL.Type.ObjectType (Argument, Field, ObjectType) as ObjectType
15+import GraphQL.Type.EnumType (EnumType) as EnumType
16+import GraphQL.Type.UnionType (UnionType) as UnionType
17+import GraphQL.Type.InputObjectType (InputField(..), InputObjectType(..)) as InputObjectType
src/GraphQL/Type/Class.pursnew file+40
@@ -0,0 +1,40 @@
1+module GraphQL.Type.Class
2+ ( class GraphQLType
3+ , introspect
4+ , class InputType
5+ , input
6+ , showDefaultValue
7+ , class OutputType
8+ , output
9+ , ExecutionContext
10+ ) where
11+
12+import Control.Monad.Error.Class (class MonadError)
13+import Data.Argonaut (Json)
14+import Data.Either (Either)
15+import Data.Map (Map)
16+import Data.Maybe (Maybe)
17+import Effect.Exception (Error)
18+import GraphQL.Execution.Result (Result)
19+import GraphQL.Language.AST as AST
20+import GraphQL.Type.Introspection.Datatypes as IntrospectionTypes
21+
22+type ExecutionContext =
23+ { variables :: Map String Json
24+ , fragments :: Map String AST.DefinitionNode
25+ }
26+
27+-- | The type class for all GraphQL types
28+class GraphQLType :: forall k. (k -> Type) -> Constraint
29+class GraphQLType t where
30+ introspect :: forall a. t a -> IntrospectionTypes.TypeIntrospection
31+
32+-- | The input type class is used for all GraphQL types that can be used as input types.
33+class GraphQLType t <= InputType t where
34+ input :: forall a. t a -> Maybe AST.ValueNode -> ExecutionContext -> Either String a
35+ showDefaultValue :: forall a. t a -> a -> String
36+
37+-- | The output type class is used for all GraphQL types that can be used as output types.
38+-- | It has instances for GraphQL types that can resolve a value within a certain monad error.
39+class (MonadError Error m, GraphQLType t) <= OutputType m t where
40+ output :: forall a. t a -> Maybe AST.SelectionSetNode -> ExecutionContext -> m a -> m Result
src/GraphQL/Type/EnumType.pursnew file+88
@@ -0,0 +1,88 @@
1+module GraphQL.Type.EnumType
2+ ( EnumType(..)
3+ , EnumValue(..)
4+ ) where
5+
6+import Prelude
7+
8+import Control.Monad.Error.Class (class MonadError, throwError)
9+import Data.Argonaut as Json
10+import Data.Either (Either(..), note)
11+import Data.List (find)
12+import Data.Map (lookup)
13+import Data.Maybe (Maybe(..))
14+import Effect.Exception (Error, error)
15+import GraphQL.Execution.Result (Result(..))
16+import GraphQL.Language.AST as AST
17+import GraphQL.Type.Class (class GraphQLType, class InputType, class OutputType, ExecutionContext)
18+import GraphQL.Type.Introspection.Datatypes as IntrospectionTypes
19+
20+
21+newtype EnumType a =
22+ EnumType
23+ { name :: String
24+ , description :: Maybe String
25+ , values :: Array (EnumValue a)
26+ }
27+
28+
29+newtype EnumValue a =
30+ EnumValue
31+ { name :: String
32+ , description :: Maybe String
33+ , value :: a
34+ , isValue :: a -> Boolean }
35+
36+
37+instance graphqlTypeEnumType :: GraphQLType EnumType where
38+ introspect (EnumType { name, description, values }) =
39+ IntrospectionTypes.EnumTypeIntrospection
40+ { name
41+ , description
42+ , enumValues: values <#> \(EnumValue val) ->
43+ IntrospectionTypes.EnumValueIntrospection
44+ { name: val.name
45+ , description: val.description
46+ , deprecationReason: Nothing
47+ }
48+ }
49+
50+
51+instance inputTypeEnumType :: InputType EnumType where
52+ input (EnumType config) (Just node) execContext =
53+ let lookupName name =
54+ note ("Unknown enum value `" <> name <> "` for type `" <> config.name <> "`.") $
55+ find (\(EnumValue val) -> val.name == name) config.values
56+ in case node of
57+ AST.VariableNode { name: AST.NameNode { value: name } } -> do
58+ json <- note ("Required variable `" <> name <> "` was not provided.") $
59+ lookup name execContext.variables
60+ EnumValue val <- Json.caseJsonString (Left "Enum values must be strings.") lookupName json
61+ pure val.value
62+
63+ AST.EnumValueNode { name: AST.NameNode { value: name } } -> do
64+ EnumValue val <- lookupName name
65+ pure val.value
66+
67+ _ -> Left "Unexpected non-enum value node for enum value."
68+
69+ input _ _ _ = Left "Missing value for required argument."
70+
71+ showDefaultValue (EnumType config) value =
72+ case find (\(EnumValue { isValue }) -> isValue value) config.values of
73+ Nothing -> "Unknown"
74+ Just (EnumValue val) -> val.name
75+
76+
77+instance outputTypeEnumType :: MonadError Error m => OutputType m EnumType where
78+ output :: forall a. EnumType a -> Maybe AST.SelectionSetNode -> ExecutionContext -> m a -> m Result
79+ output (EnumType config) Nothing _ mValue = do
80+ value <- mValue
81+ case find (\(EnumValue { isValue }) -> isValue value) config.values of
82+ Nothing ->
83+ throwError $ error "Could not select enum value representation from provided value."
84+
85+ Just (EnumValue val) ->
86+ pure $ ResultLeaf $ Json.fromString val.name
87+
88+ output _ _ _ _ = pure $ ResultError "Invalid subselection on enum type!"
src/GraphQL/Type/InputObjectType.pursnew file+53
@@ -0,0 +1,53 @@
1+module GraphQL.Type.InputObjectType where
2+
3+import Prelude
4+
5+import Control.Lazy (class Lazy)
6+import Data.Either (Either)
7+import Data.Maybe (Maybe)
8+import Data.Newtype (class Newtype, unwrap)
9+import GraphQL.Language.AST as AST
10+import GraphQL.Type.Class (class GraphQLType, class InputType, ExecutionContext)
11+import GraphQL.Type.Introspection.Datatypes as IntrospectionTypes
12+import Type.Proxy (Proxy)
13+
14+
15+newtype InputObjectType a = InputObjectType (Unit ->
16+ { name :: String
17+ , description :: Maybe String
18+ , fieldIntrospection :: Array IntrospectionTypes.InputValueIntrospection
19+ , input :: Maybe AST.ValueNode -> ExecutionContext -> Either String a
20+ , showDefaultValue :: a -> String
21+ }
22+)
23+
24+
25+derive instance newtypeInputObjectType :: Newtype (InputObjectType a) _
26+
27+
28+instance graphqlTypeInputObjectType :: GraphQLType InputObjectType where
29+ introspect (InputObjectType config) =
30+ IntrospectionTypes.InputObjectTypeIntrospection
31+ { name: (config unit).name
32+ , description: (config unit).description
33+ , inputFields: (config unit).fieldIntrospection
34+ }
35+
36+
37+instance inputTypeInputObjectType :: InputType InputObjectType where
38+ input (InputObjectType config) = (config unit).input
39+ showDefaultValue (InputObjectType config) = (config unit).showDefaultValue
40+
41+
42+instance lazyInputObjectType :: Lazy (InputObjectType a) where
43+ defer fn = InputObjectType $ \_ -> unwrap (fn unit) unit
44+
45+
46+newtype InputField :: forall k. k -> Type -> Type
47+newtype InputField l a = InputField
48+ { name :: Proxy l
49+ , required :: Boolean
50+ , introspection :: IntrospectionTypes.InputValueIntrospection
51+ , input :: Maybe AST.ValueNode -> ExecutionContext -> Either String a
52+ , showDefaultValue :: a -> String
53+ }
src/GraphQL/Type/Introspection/Datatypes.pursnew file+174
@@ -0,0 +1,174 @@
1+module GraphQL.Type.Introspection.Datatypes where
2+
3+import Prelude
4+
5+import Data.Enum (class Enum)
6+import Data.Generic.Rep (class Generic)
7+import Data.Bounded.Generic (genericBottom, genericTop)
8+import Data.Enum.Generic (genericPred, genericSucc)
9+import Data.Eq.Generic (genericEq)
10+import Data.Ord.Generic (genericCompare)
11+import Data.Maybe (Maybe(..))
12+import Data.Newtype (class Newtype)
13+
14+newtype SchemaIntrospection = SchemaIntrospection
15+ { queryType :: TypeIntrospection
16+ , mutationType :: Maybe TypeIntrospection
17+ }
18+
19+
20+derive instance newtypeSchemaIntrospection :: Newtype SchemaIntrospection _
21+
22+
23+-- | This data type is used to gather information at runtime about the schema. Each GraphQL type can
24+-- | be introspected and has to return some information about its structure.
25+data TypeIntrospection
26+ = ScalarTypeIntrospection
27+ { name :: String
28+ , description :: Maybe String
29+ }
30+ | ObjectTypeIntrospection
31+ { name :: String
32+ , description :: Maybe String
33+ , fields :: Array FieldIntrospection
34+ }
35+ | EnumTypeIntrospection
36+ { name :: String
37+ , description :: Maybe String
38+ , enumValues :: Array EnumValueIntrospection
39+ }
40+ | InputObjectTypeIntrospection
41+ { name :: String
42+ , description :: Maybe String
43+ , inputFields :: Array InputValueIntrospection
44+ }
45+ | UnionTypeIntrospection
46+ { name :: String
47+ , description :: Maybe String
48+ , possibleTypes :: Unit -> Array TypeIntrospection
49+ }
50+ | ListTypeIntrospection
51+ { ofType :: Unit -> TypeIntrospection }
52+ | NonNullTypeIntrospection
53+ { ofType :: Unit -> TypeIntrospection }
54+
55+
56+-- | Read the name of a type from a type introspection. Not all types have names: List and
57+-- | non-null types don't have names on their own.
58+getName :: TypeIntrospection -> Maybe String
59+getName (ScalarTypeIntrospection { name }) = Just name
60+getName (ObjectTypeIntrospection { name }) = Just name
61+getName (InputObjectTypeIntrospection { name }) = Just name
62+getName (EnumTypeIntrospection { name }) = Just name
63+getName (UnionTypeIntrospection { name }) = Just name
64+getName _ = Nothing
65+
66+
67+-- | Read the description of a type from a type introspection.
68+getDescription :: TypeIntrospection -> Maybe String
69+getDescription (ScalarTypeIntrospection { description }) = description
70+getDescription (ObjectTypeIntrospection { description }) = description
71+getDescription (InputObjectTypeIntrospection { description }) = description
72+getDescription (EnumTypeIntrospection { description }) = description
73+getDescription (UnionTypeIntrospection { description }) = description
74+getDescription _ = Nothing
75+
76+
77+-- | Get the type kind of an introspection
78+getTypeKind :: TypeIntrospection -> TypeKind
79+getTypeKind (ScalarTypeIntrospection _) = Scalar
80+getTypeKind (ObjectTypeIntrospection _) = Object
81+getTypeKind (InputObjectTypeIntrospection _) = InputObject
82+getTypeKind (EnumTypeIntrospection _) = Enum
83+getTypeKind (UnionTypeIntrospection _) = Union
84+getTypeKind (ListTypeIntrospection _) = List
85+getTypeKind (NonNullTypeIntrospection _) = NonNull
86+
87+
88+-- We can abuse the fact that our schema can only have unique type names to create an efficient Eq
89+-- instance to only compare the names of two types
90+instance eqTypeIntrospection :: Eq TypeIntrospection where
91+ eq t1 t2 = getName t1 == getName t2
92+
93+
94+-- We can abuse the fact that our schema can only have unique type names to create an efficient Ord
95+-- instance
96+instance ordTypeIntrospection :: Ord TypeIntrospection where
97+ compare t1 t2 = compare (getName t1) (getName t2)
98+
99+
100+newtype EnumValueIntrospection = EnumValueIntrospection
101+ { name :: String
102+ , description :: Maybe String
103+ , deprecationReason :: Maybe String
104+ }
105+
106+
107+derive instance newtypeEnumValueIntrospection :: Newtype EnumValueIntrospection _
108+
109+
110+newtype FieldIntrospection = FieldIntrospection
111+ { name :: String
112+ , description :: Maybe String
113+ , args :: Array InputValueIntrospection
114+ , type :: Unit -> TypeIntrospection
115+ , deprecationReason :: Maybe String
116+ }
117+
118+
119+derive instance newtypeFieldIntrospection :: Newtype FieldIntrospection _
120+
121+
122+newtype InputValueIntrospection = InputValueIntrospection
123+ { name :: String
124+ , description :: Maybe String
125+ , type :: Unit -> TypeIntrospection
126+ , defaultValue :: Maybe String
127+ }
128+
129+
130+derive instance newtypeInputValueIntrospection :: Newtype InputValueIntrospection _
131+
132+
133+-- | An enum value for different GraphQL kinds
134+data TypeKind
135+ = Scalar
136+ | Object
137+ | Interface
138+ | Union
139+ | Enum
140+ | InputObject
141+ | List
142+ | NonNull
143+
144+
145+derive instance genericTypeKind :: Generic TypeKind _
146+
147+
148+instance eqTypeKind :: Eq TypeKind where
149+ eq = genericEq
150+
151+
152+instance ordTypeKind :: Ord TypeKind where
153+ compare = genericCompare
154+
155+
156+instance boundedTypeKind :: Bounded TypeKind where
157+ top = genericTop
158+ bottom = genericBottom
159+
160+
161+instance enumTypeKind :: Enum TypeKind where
162+ succ = genericSucc
163+ pred = genericPred
164+
165+
166+instance showTypeKind :: Show TypeKind where
167+ show Scalar = "SCALAR"
168+ show Object = "OBJECT"
169+ show Interface = "INTERFACE"
170+ show Union = "UNION"
171+ show Enum = "ENUM"
172+ show InputObject = "INPUT_OBJECT"
173+ show List = "LIST"
174+ show NonNull = "NON_NULL"
src/GraphQL/Type/Introspection/Util.pursnew file+76
@@ -0,0 +1,76 @@
1+module GraphQL.Type.Introspection.Util where
2+
3+import Prelude
4+
5+import Data.Foldable (foldl)
6+import Data.Maybe (Maybe(..), maybe)
7+import Data.Set (Set, empty, filter, insert, member, toUnfoldable)
8+import GraphQL.Type.Introspection.Datatypes (FieldIntrospection(..), InputValueIntrospection(..), SchemaIntrospection(..), TypeIntrospection(..), getName)
9+
10+
11+collectTypes :: SchemaIntrospection -> Set TypeIntrospection
12+collectTypes (SchemaIntrospection { queryType, mutationType }) =
13+ collectTypesRec queryType empty <> maybe empty (flip collectTypesRec empty) mutationType
14+ where
15+ collectTypesRec :: TypeIntrospection -> Set TypeIntrospection -> Set TypeIntrospection
16+ -- If the type is a wrapper type, we try to insert the inner type
17+ collectTypesRec (ListTypeIntrospection { ofType }) set = collectTypesRec (ofType unit) set
18+
19+ collectTypesRec (NonNullTypeIntrospection { ofType }) set = collectTypesRec (ofType unit) set
20+
21+ -- If the type has fields we need to recursively go over these fields and add the type of the
22+ -- fields as well
23+ collectTypesRec introspection@(ObjectTypeIntrospection { fields }) set =
24+ if member introspection set
25+ then set
26+ else foldl collectTypesFromField (insert introspection set) fields
27+
28+ -- Same for union types that have multiple possible types
29+ collectTypesRec introspection@(UnionTypeIntrospection { possibleTypes }) set =
30+ if member introspection set
31+ then set
32+ else foldl (flip collectTypesRec) (insert introspection set) (possibleTypes unit)
33+
34+ -- If the type has no fields we can simply return a set with one element
35+ collectTypesRec introspection set =
36+ insert introspection set
37+
38+ collectTypesFromField :: Set TypeIntrospection -> FieldIntrospection -> Set TypeIntrospection
39+ collectTypesFromField set (FieldIntrospection config) =
40+ let
41+ argumentTypes = config.args
42+ resultType = config.type unit
43+ newSet = foldl collectTypesFromArg set argumentTypes
44+ in
45+ if member resultType newSet then newSet else collectTypesRec resultType newSet
46+
47+ collectTypesFromArg ::
48+ Set TypeIntrospection ->
49+ InputValueIntrospection ->
50+ Set TypeIntrospection
51+ collectTypesFromArg set (InputValueIntrospection config) =
52+ let
53+ inputType = getNamedType $ config.type unit
54+ in
55+ if member inputType set then set else
56+ let
57+ newSet = case inputType of
58+ -- We have to recursively add all the input object type's fields as well
59+ (InputObjectTypeIntrospection { inputFields: fields }) ->
60+ foldl collectTypesFromArg set fields
61+
62+ -- Or if this type is just a trivial input type we can go on with the current set
63+ _ -> set
64+ in
65+ insert inputType newSet
66+
67+
68+getNamedType :: TypeIntrospection -> TypeIntrospection
69+getNamedType (ListTypeIntrospection { ofType }) = getNamedType (ofType unit)
70+getNamedType (NonNullTypeIntrospection { ofType }) = getNamedType (ofType unit)
71+getNamedType t = t
72+
73+
74+findTypeByName :: String -> SchemaIntrospection -> Maybe TypeIntrospection
75+findTypeByName name schemaIntrospection =
76+ toUnfoldable $ filter (getName >>> (_ == Just name)) $ collectTypes schemaIntrospection
src/GraphQL/Type/ObjectType.pursnew file+136
@@ -0,0 +1,136 @@
1+module GraphQL.Type.ObjectType
2+ ( ObjectType(..)
3+ , ExecutableField(..)
4+ , Field(..)
5+ , Argument(..)
6+ ) where
7+
8+import Prelude
9+
10+import Control.Lazy (class Lazy)
11+import Control.Monad.Error.Class (class MonadError, catchError)
12+import Data.Argonaut as Json
13+import Data.Either (Either)
14+import Data.List (List, singleton)
15+import Data.Map (Map, lookup)
16+import Data.Maybe (Maybe(..), fromMaybe)
17+import Data.Newtype (class Newtype, unwrap)
18+import Data.Traversable (sequence)
19+import Data.Tuple (Tuple(..))
20+import Effect.Exception (Error, message)
21+import GraphQL.Execution.Result (Result(..))
22+import GraphQL.Language.AST as AST
23+import GraphQL.OptionallyParallel (class OptionallyParallel, optionallyParallel, optionallySequential)
24+import GraphQL.Type.Class (class GraphQLType, class OutputType, ExecutionContext)
25+import GraphQL.Type.Introspection.Datatypes as IntrospectionTypes
26+
27+
28+newtype ObjectType m a =
29+ ObjectType (Unit ->
30+ { name :: String
31+ , fields :: Map String (ExecutableField m a)
32+ , introspection :: IntrospectionTypes.TypeIntrospection
33+ }
34+ )
35+
36+
37+derive instance newtypeObjectType :: Newtype (ObjectType m a) _
38+
39+
40+instance graphqlTypeObjectType :: GraphQLType (ObjectType m) where
41+ introspect (ObjectType configFn) = (configFn unit).introspection
42+
43+
44+instance (MonadError Error m, OptionallyParallel f m) => OutputType m (ObjectType m) where
45+ -- output :: forall t a. t a -> Maybe AST.SelectionSetNode -> ExecutionContext -> m a -> m Result
46+ output (ObjectType fno) (Just (AST.SelectionSetNode { selections })) execCtx mValue = do
47+ value <- mValue
48+ let allFields = selections >>= collectField
49+ let resolvingFields = serializeField value <$> allFields
50+ map ResultObject $ (optionallySequential :: f ~> m) $ sequence $ (optionallyParallel :: m ~> f ) <$> resolvingFields
51+ where
52+ -- | Flatten the selection node structure by spreading all fragments into the list
53+ collectField :: AST.SelectionNode -> List AST.SelectionNode
54+ collectField n@(AST.FieldNode _) = singleton n
55+ collectField (AST.InlineFragmentNode {
56+ selectionSet: (AST.SelectionSetNode { selections: s })
57+ }) = collectField =<< s
58+ collectField (AST.FragmentSpreadNode { name: AST.NameNode n }) =
59+ case lookup n.value execCtx.fragments of
60+ Just (AST.FragmentDefinitionNode {
61+ selectionSet: AST.SelectionSetNode { selections: s }
62+ }) -> collectField =<< s
63+ _ -> mempty
64+
65+ -- serializeField :: a -> AST.SelectionNode -> m (Tuple String Result)
66+ serializeField value node@(AST.FieldNode fld) = do
67+ let (AST.NameNode { value: name }) = fld.name
68+ let (AST.NameNode { value: alias }) = fromMaybe fld.name fld.alias
69+ let o = fno unit
70+ case lookup name o.fields of
71+ Just (ExecutableField { execute }) ->
72+ Tuple alias <$>
73+ (flip catchError (message >>> ResultError >>> pure) $
74+ execute value node execCtx)
75+ Nothing ->
76+ if
77+ name == "__typename"
78+ then
79+ pure $ Tuple alias $ ResultLeaf $ Json.fromString o.name
80+ else
81+ pure $ Tuple alias $
82+ ResultError ("Unknown field `" <> name <> "` on type `" <> o.name <> "`.")
83+ -- TODO: This branch needs fixing. It is for fragment spreads and so on. Maybe normalise
84+ -- the query first and completely eliminate the branch...
85+ serializeField _ _ = pure $ Tuple "unknown" $ ResultError "Unexpected fragment spread!"
86+
87+ output _ _ _ _ = pure $ ResultError "Missing subselection on object type."
88+
89+
90+instance showObjectType :: Show (ObjectType m a) where
91+ show (ObjectType config) = "type " <> (config unit).name
92+
93+
94+instance lazyObjectType :: Lazy (ObjectType m a) where
95+ defer fn = ObjectType $ \_ -> unwrap (fn unit) unit
96+
97+
98+-- | The executable field loses the information about it's arguments types. This is needed to add it
99+-- | to the map of arguments of the object type. The execute function will extract the arguments of
100+-- | the field from the AST.
101+newtype ExecutableField m a =
102+ ExecutableField { execute :: a -> AST.SelectionNode -> ExecutionContext -> m Result }
103+
104+
105+derive instance newtypeExecutableField :: Newtype (ExecutableField m a) _
106+
107+
108+-- | Object types can have fields. Fields are constructed using the `field` function from this
109+-- | module and added to object types using the `:>` operator.
110+newtype Field m a argsd argsp =
111+ Field
112+ { name :: String
113+ , description :: Maybe String
114+ , typeIntrospection :: Unit -> IntrospectionTypes.TypeIntrospection
115+ , argumentIntrospections :: Array IntrospectionTypes.InputValueIntrospection
116+ , args :: Record argsd
117+ , serialize :: AST.SelectionNode -> ExecutionContext -> Record argsp -> a -> m Result
118+ }
119+
120+
121+derive instance newtypeField :: Newtype (Field m a argsd argsp) _
122+
123+
124+-- | Fields can have multiple arguments. Arguments are constructed using the `arg` function from
125+-- | this module and the `?>` operator.
126+newtype Argument a =
127+ Argument
128+ { description :: Maybe String
129+ , typeIntrospection :: Unit -> IntrospectionTypes.TypeIntrospection
130+ , resolveValue :: Maybe AST.ValueNode -> ExecutionContext -> Either String a
131+ , defaultValue :: Maybe a
132+ , showDefaultValue :: a -> String
133+ }
134+
135+
136+derive instance newtypeArgument :: Newtype (Argument a) _
src/GraphQL/Type/ScalarType.pursnew file+57
@@ -0,0 +1,57 @@
1+module GraphQL.Type.ScalarType
2+ ( ScalarType(..)
3+ ) where
4+
5+
6+import Prelude
7+
8+import Control.Monad.Error.Class (class MonadError)
9+import Data.Argonaut (Json, stringify)
10+import Data.Either (Either(..), note)
11+import Data.Map (lookup)
12+import Data.Maybe (Maybe(..))
13+import Effect.Exception (Error)
14+import GraphQL.Execution.Result (Result(..))
15+import GraphQL.Language.AST as AST
16+import GraphQL.Type.Class (class GraphQLType, class InputType, class OutputType)
17+import GraphQL.Type.Introspection.Datatypes (TypeIntrospection(..))
18+
19+
20+-- | Scalar types are the leaf nodes of a GraphQL schema. Scalar types can be serialised into JSON
21+-- | or obtained from a JSON when read from the variables provided by a query. Furthermore values
22+-- | can be read from literals in a GraphQL document. To create a scalar type a name and optionally
23+-- | a description need to be provided.
24+-- | The functions `parseLiteral`, `parseValue` and `serialize` are used to convert between the
25+-- | GraphQL transport formats and PureScript representations.
26+-- |
27+-- | The GraphQL PureScript implementation comes with the five default scalars defined in the
28+-- | specification.
29+newtype ScalarType a =
30+ ScalarType
31+ { name :: String
32+ , description :: Maybe String
33+ , parseLiteral :: AST.ValueNode -> Either String a
34+ , parseValue :: Json -> Either String a
35+ , serialize :: a -> Json
36+ }
37+
38+
39+instance graphqlTypeScalarType :: GraphQLType ScalarType where
40+ introspect (ScalarType { name, description }) = ScalarTypeIntrospection { name, description }
41+
42+
43+instance inputTypeScalarType :: InputType ScalarType where
44+ input (ScalarType config) (Just node) execCtx = case node of
45+ (AST.VariableNode { name: AST.NameNode { value }}) -> do
46+ json <- note ("Required variable `" <> value <> "` was not provided.") $
47+ lookup value execCtx.variables
48+ config.parseValue json
49+ _ -> config.parseLiteral node
50+ input _ Nothing _ = Left "Must provide value for required scalar."
51+
52+ showDefaultValue (ScalarType config) = config.serialize >>> stringify
53+
54+
55+instance outputTypeScalarType :: (MonadError Error m) => OutputType m ScalarType where
56+ output (ScalarType s) Nothing _ val = ResultLeaf <$> map s.serialize val
57+ output _ _ _ _ = pure $ ResultError "Invalid subselection on scalar type!"
src/GraphQL/Type/Schema.pursnew file+8
@@ -0,0 +1,8 @@
1+module GraphQL.Type.Schema (Schema(..)) where
2+
3+import Data.Maybe (Maybe)
4+import GraphQL.Type.ObjectType (ObjectType)
5+
6+
7+-- | The schema contains the central entry points for GraphQL queries.
8+newtype Schema m a = Schema { query :: ObjectType m a, mutation :: Maybe (ObjectType m a) }
src/GraphQL/Type/UnionType.pursnew file+57
@@ -0,0 +1,57 @@
1+module GraphQL.Type.UnionType where
2+
3+import Prelude
4+
5+import Control.Monad.Error.Class (class MonadError)
6+import Data.List (filter)
7+import Data.Map (lookup)
8+import Data.Maybe (Maybe(..))
9+import Effect.Exception (Error)
10+import GraphQL.Execution.Result (Result)
11+import GraphQL.Language.AST as AST
12+import GraphQL.Language.AST.Util (nameFromNameNode)
13+import GraphQL.Type.Class (class GraphQLType, class OutputType, ExecutionContext)
14+import GraphQL.Type.Introspection.Datatypes as IntrospectionTypes
15+
16+
17+newtype UnionType m a = UnionType (Unit ->
18+ { name :: String
19+ , description :: Maybe String
20+ , typeIntrospections :: Array IntrospectionTypes.TypeIntrospection
21+ , output :: Maybe AST.SelectionSetNode -> ExecutionContext -> m a -> m Result
22+ }
23+)
24+
25+
26+instance graphqlTypeUnionType :: GraphQLType (UnionType m) where
27+ introspect (UnionType config) = IntrospectionTypes.UnionTypeIntrospection
28+ { name: (config unit).name
29+ , description: (config unit).description
30+ , possibleTypes: \_ -> (config unit).typeIntrospections
31+ }
32+
33+
34+-- Takes a string and only returns part of the selection set that matches the return type
35+-- TODO: Throw under certain cases, e.g. if there is a field selected in the root that is not
36+-- `__typename`
37+filterSelectionSet :: String -> AST.SelectionSetNode -> ExecutionContext -> AST.SelectionSetNode
38+filterSelectionSet typeName (AST.SelectionSetNode { selections }) ctx =
39+ AST.SelectionSetNode { selections: filter filterFn selections }
40+ where
41+ -- Only the __typename field is allowed on the root selection
42+ filterFn (AST.FieldNode { name: AST.NameNode { value }}) = value == "__typename"
43+
44+ -- If we find a fragment we only include it into the selection if it matches the type
45+ filterFn (AST.FragmentSpreadNode { name: AST.NameNode { value }}) =
46+ case lookup value ctx.fragments of
47+ Just (AST.FragmentDefinitionNode { typeCondition: AST.SimpleNamedTypeNode { name }}) ->
48+ nameFromNameNode name == typeName
49+ _ -> false
50+
51+ -- Same thing for inline fragment only here we don't have to lookup the fragment
52+ filterFn (AST.InlineFragmentNode { typeCondition: AST.SimpleNamedTypeNode { name } }) =
53+ nameFromNameNode name == typeName
54+
55+instance outputTypeUnionType :: (MonadError Error m) => OutputType m (UnionType m) where
56+ output :: forall a. UnionType m a -> Maybe AST.SelectionSetNode -> ExecutionContext -> m a -> m Result
57+ output (UnionType config) = (config unit).output
test/Async.pursnew file+42
@@ -0,0 +1,42 @@
1+module Test.Async where
2+
3+import Prelude
4+
5+import Data.Argonaut (stringify)
6+import Data.DateTime as DateTime
7+import Data.Map as Map
8+import Data.Maybe (Maybe(..))
9+import Data.Time.Duration (Milliseconds(..))
10+import Effect.Aff (Aff, delay)
11+import Effect.Class (liftEffect)
12+import Effect.Now (nowDateTime)
13+import GraphQL ((.>), (:>), (!>))
14+import GraphQL as GraphQL
15+import Test.Spec (Spec, describe, it)
16+import Test.Spec.Assertions (shouldEqual, shouldSatisfy)
17+
18+schema :: GraphQL.Schema Aff Unit
19+schema = GraphQL.Schema { query: queryType, mutation: Nothing }
20+
21+queryType :: GraphQL.ObjectType Aff Unit
22+queryType =
23+ GraphQL.objectType "Query"
24+ :> "The root query type."
25+ .> GraphQL.field "async" GraphQL.string
26+ :> "An asynchronous field."
27+ !> asyncResolver
28+
29+asyncResolver :: forall parent args. parent -> args -> Aff String
30+asyncResolver _ _ = do
31+ delay (Milliseconds 1000.0)
32+ pure "Hello, World!"
33+
34+asyncTest :: Spec Unit
35+asyncTest = describe "Parallel" $ do
36+ it "resolves two fields in parallel" $ do
37+ let query = "{ a: async b: async }"
38+ startedAt <- liftEffect nowDateTime
39+ result <- GraphQL.graphql schema query Map.empty Nothing unit
40+ finishedAt <- liftEffect nowDateTime
41+ stringify result `shouldEqual` "{\"data\":{\"a\":\"Hello, World!\",\"b\":\"Hello, World!\"}}"
42+ DateTime.diff finishedAt startedAt `shouldSatisfy` (_ < Milliseconds 2000.0)
test/Execution.purs+169−54
@@ -3,24 +3,27 @@ module Test.GraphQL.Execution where
33import Prelude
44
55import Data.Argonaut.Core (stringify)
6−import Data.Either (Either(..))
6+import Data.Argonaut.Core as Json
7+import Data.Array (length)
8+import Data.Bounded.Generic (genericBottom, genericTop)
9+import Data.Either (Either(..), either, note)
710import Data.Enum (class Enum)
11+import Data.Enum.Generic (genericPred, genericSucc)
812import Data.Generic.Rep (class Generic)
9−import Data.Generic.Rep.Bounded (genericBottom, genericTop)
10−import Data.Generic.Rep.Enum (genericPred, genericSucc)
11−import Data.Generic.Rep.Eq (genericEq)
12−import Data.Generic.Rep.Ord (genericCompare)
13−import Data.Maybe (Maybe(..))
13+import Data.Map as Map
14+import Data.Maybe (Maybe(..), fromMaybe)
1415import Data.Newtype (class Newtype, unwrap)
1516import Data.String (trim)
16−import Data.Symbol (SProxy(..))
17−import Effect.Aff (Aff, Error, throwError, error)
18−import GraphQL (graphql)
19−import GraphQL.Type ((!>), (.>), (:>), (?>), (!#>), (!!>))
20−import GraphQL.Type as GQL
21−import GraphQL.Type.Scalar as Scalar
17+import Data.Traversable (for_)
18+import Data.Variant (Variant, inj)
19+import Effect.Aff (Aff, Error, error, throwError)
20+import Foreign.Object as Object
21+import GraphQL ((!!>), (!#>), (!>), (.>), (:>), (?>))
22+import GraphQL as GraphQL
23+import GraphQL.DSL (withDefaultValue)
2224import Test.Spec (Spec, describe, it)
2325import Test.Spec.Assertions (fail, shouldEqual)
26+import Type.Proxy (Proxy(..))
2427
2528-- Some data types for out upcoming tests
2629
@@ -32,11 +35,9 @@ data UserLevel = NormalUser | Moderator | Admin
3235
3336derive instance genericUserLevel :: Generic UserLevel _
3437
35−instance eqUserLevel :: Eq UserLevel where
36− eq = genericEq
38+derive instance Eq UserLevel
3739
38−instance ordUserLevel :: Ord UserLevel where
39− compare = genericCompare
40+derive instance Ord UserLevel
4041
4142instance boundedUserLevel :: Bounded UserLevel where
4243 top = genericTop
@@ -52,65 +53,103 @@ instance showUserLevel :: Show UserLevel where
5253 show NormalUser = "USER"
5354
5455
55−testSchema :: GQL.Schema (Either Error) String
56−testSchema = GQL.Schema { query: queryType }
56+testSchema :: GraphQL.Schema (Either Error) String
57+testSchema = GraphQL.Schema { query: queryType, mutation: Nothing }
5758
5859
59−queryType :: GQL.ObjectType (Either Error) String
60+queryType :: GraphQL.ObjectType (Either Error) String
6061queryType =
61− GQL.objectType "Query"
62− .> "The root query type"
63− :> GQL.field "hello" Scalar.string
64− .> "A simple test field that connects the root string with a greeting."
65− !> (\_ -> map (\p -> "Hello " <> p <> "!"))
66− :> GQL.field "greet" Scalar.string
67− .> "A field that takes a name and responds with a presonalized greeting."
68− ?> GQL.arg Scalar.string (SProxy :: SProxy "name")
62+ GraphQL.objectType "Query"
63+ :> "The root query type"
64+ .> GraphQL.field "hello" GraphQL.string
65+ :> "A simple test field that connects the root string with a greeting."
66+ !> (\_ p -> pure $ "Hello " <> p <> "!")
67+ .> GraphQL.field "greet" GraphQL.string
68+ :> "A field that takes a name and responds with a presonalized greeting."
69+ ?> GraphQL.arg @"name" GraphQL.string
6970 !> (\{ name } _ -> pure $ "Greetings " <> name <> "!")
70− :> GQL.field "test" Scalar.int
71− !!> (_ $> 42)
72− :> GQL.field "nested" userType
73− !!> (_ $> User { id: "user1", name: "Hendrik", age: 25, level: NormalUser })
74− :> GQL.listField "someList" Scalar.string
75− !!> (_ $> ["This", "is", "a", "little", "list"])
76− :> GQL.nullableField "nullable" Scalar.float
77− !!> (_ $> Nothing)
78− :> GQL.field "reflect" Scalar.string
79− ?> GQL.arg userLevelType (SProxy :: _ "argIn")
71+ .> GraphQL.field "test" GraphQL.int
72+ !#> const 42
73+ .> GraphQL.field "nested" userType
74+ !#> (const $ User { id: "user1", name: "Hendrik", age: 25, level: NormalUser })
75+ .> GraphQL.listField "someList" GraphQL.string
76+ !#> (const ["This", "is", "a", "little", "list"])
77+ .> GraphQL.nullableField "nullable" GraphQL.float
78+ !#> (const Nothing)
79+ .> GraphQL.field "reflect" GraphQL.string
80+ ?> GraphQL.arg @"argIn" userLevelType
8081 !> (\{ argIn } _ -> pure $ show argIn)
81− :> GQL.field "toggle" Scalar.boolean
82− ?> GQL.arg Scalar.boolean (SProxy :: _ "on")
82+ .> GraphQL.field "reflectStringOptional" GraphQL.string
83+ ?> GraphQL.optionalArg @"argIn" GraphQL.string
84+ !> (\{ argIn } _ -> pure $ fromMaybe "default" argIn)
85+ .> GraphQL.field "reflectStringDefault" GraphQL.string
86+ ?> GraphQL.arg @"argIn" GraphQL.string `withDefaultValue` "default"
87+ !> (\{ argIn } _ -> pure argIn)
88+ .> GraphQL.field "reflectStringDefaultOptional" GraphQL.string
89+ ?> GraphQL.optionalArg @"argIn" GraphQL.string `withDefaultValue` pure "default"
90+ !> (\{ argIn } _ -> pure $ fromMaybe "null" argIn)
91+ .> GraphQL.field "toggle" GraphQL.boolean
92+ ?> GraphQL.arg @"on" GraphQL.boolean
8393 !> (\{ on: onArg } _ -> pure $ not onArg)
84− :> GQL.nullableField "fail" Scalar.boolean
94+ .> GraphQL.nullableField "fail" GraphQL.boolean
8595 !!> (\_ -> throwError $ error "Always fails at runtime.")
96+ .> GraphQL.field "unionField" exampleUnionType
97+ ?> GraphQL.arg @"type" GraphQL.string
98+ !> resolveUnion
8699
87100
88−userType :: GQL.ObjectType (Either Error) User
101+resolveUnion :: { "type" :: String } -> String -> (Either Error) ExampleVariant
102+resolveUnion args _ = case args.type of
103+ "user" -> pure $ inj (Proxy :: _ "user") $ User { id: "user1", name: "Hendrik", age: 25, level: NormalUser }
104+ "test" -> pure $ inj (Proxy :: _ "test") "test"
105+ _ -> throwError $ error "Unknown type"
106+
107+
108+type ExampleVariant = Variant (user :: User, test :: String)
109+
110+
111+exampleUnionType :: GraphQL.UnionType (Either Error) ExampleVariant
112+exampleUnionType = GraphQL.union "ExampleUnion" { user: userType, test: testType }
113+
114+
115+testType :: GraphQL.ObjectType (Either Error) String
116+testType =
117+ GraphQL.objectType "Test"
118+ :> "A test type"
119+ .> GraphQL.field "test" GraphQL.string
120+ !#> const "test"
121+
122+
123+
124+userType :: GraphQL.ObjectType (Either Error) User
89125userType =
90− GQL.objectType "User"
91− .> "A type for all users in the database"
92− :> GQL.field "id" Scalar.string
126+ GraphQL.objectType "User"
127+ :> "A type for all users in the database"
128+ .> GraphQL.field "id" GraphQL.string
93129 !#> unwrap >>> _.id
94− :> GQL.field "name" Scalar.string
130+ .> GraphQL.field "name" GraphQL.string
95131 !#> unwrap >>> _.name
96− :> GQL.field "age" Scalar.int
132+ .> GraphQL.field "age" GraphQL.int
97133 !#> unwrap >>> _.age
98− :> GQL.field "level" userLevelType
134+ .> GraphQL.field "level" userLevelType
99135 !#> unwrap >>> _.level
100136
101137
102−userLevelType :: GQL.EnumType UserLevel
138+userLevelType :: GraphQL.EnumType UserLevel
103139userLevelType =
104− GQL.enumType "UserLevel"
105− .> "An enum type to denominate the user level."
140+ GraphQL.enumType "UserLevel"
141+ :> "An enum type to denominate the user level."
106142
107143
108144testQuery :: String -> String -> Aff Unit
109−testQuery query expected = case map stringify (graphql testSchema query (pure "Hendrik")) of
110− Right res -> res `shouldEqual` expected
145+testQuery query expected =
146+ case GraphQL.graphql testSchema query Map.empty Nothing "Hendrik" of
147+ Right res -> stringify res `shouldEqual` expected
111148
112− Left _ -> fail "failed to execute query"
149+ Left message -> fail $ show message
113150
151+affFromEither :: Either Error ~> Aff
152+affFromEither = either throwError pure
114153
115154executionSpec :: Spec Unit
116155executionSpec =
@@ -174,7 +213,7 @@ executionSpec =
174213 """{ toggle(on: false) }"""
175214 """{"data":{"toggle":true}}"""
176215
177− it "Catches errors thrown inside of resolvers" $
216+ it "catches errors thrown inside of resolvers" $
178217 testQuery
179218 """{ fail }""" $
180219 trim """
@@ -188,3 +227,79 @@ executionSpec =
188227 testQuery
189228 """{ nested { __typename } }"""
190229 """{"data":{"nested":{"__typename":"User"}}}"""
230+
231+ it "wraps optional parameters in maybe" do
232+ testQuery
233+ """{ reflectStringOptional }"""
234+ """{"data":{"reflectStringOptional":"default"}}"""
235+ testQuery
236+ """{ reflectStringOptional(argIn: "Hello World") }"""
237+ """{"data":{"reflectStringOptional":"Hello World"}}"""
238+
239+ it "accepts null as a value for an optional parameter" $
240+ testQuery
241+ """{ reflectStringOptional(argIn: null) }"""
242+ """{"data":{"reflectStringOptional":"default"}}"""
243+
244+ it "accepts null as a variable value for an optional parameter" $ affFromEither do
245+ let query = "query ($arg: String) { reflectStringOptional(argIn: $arg) }"
246+ res <- GraphQL.graphql testSchema query (Map.insert "arg" Json.jsonNull Map.empty) Nothing ""
247+ stringify res `shouldEqual` """{"data":{"reflectStringOptional":"default"}}"""
248+
249+ it "uses the default value for arguments with default value if no value is given" $
250+ testQuery
251+ """{ reflectStringDefault }"""
252+ """{"data":{"reflectStringDefault":"default"}}"""
253+
254+ it "throws an error for null values provided for non-nullable arguments with default" do
255+ let queries =
256+ [ "{ reflectStringDefault(argIn: null) }"
257+ , "query ($arg: String) { reflectStringDefault(argIn: $arg) }"
258+ ]
259+ for_ queries \query -> affFromEither do
260+ res <- GraphQL.graphql testSchema query (Map.insert "arg" Json.jsonNull Map.empty) Nothing ""
261+ errorsArray <- note (error "no error property in result JSON") $
262+ Json.toObject res >>= Object.lookup "errors" >>= Json.toArray
263+ length errorsArray `shouldEqual` 1
264+
265+ it "calls the resolver with Nothing for optional arguments if null is given" do
266+ testQuery
267+ """{ reflectStringDefaultOptional(argIn: null) }"""
268+ """{"data":{"reflectStringDefaultOptional":"null"}}"""
269+
270+ it "returns the right type name on union types" do
271+ testQuery
272+ """{ unionField(type: "user") { __typename } }"""
273+ """{"data":{"unionField":{"__typename":"User"}}}"""
274+ testQuery
275+ """{ unionField(type: "test") { __typename } }"""
276+ """{"data":{"unionField":{"__typename":"Test"}}}"""
277+
278+ it "resolves union type data correctly" do
279+ testQuery
280+ """{ unionField(type: "user") { ... on User { id } } }"""
281+ """{"data":{"unionField":{"id":"user1"}}}"""
282+ testQuery
283+ """{ unionField(type: "test") { ... on Test { test } } }"""
284+ """{"data":{"unionField":{"test":"test"}}}"""
285+
286+
287+introspectionSpec :: Spec Unit
288+introspectionSpec =
289+ describe "Introspection" do
290+ describe "__type" do
291+ it "returns type introspection by their name" do
292+ testQuery
293+ """{ __type(name: "User") { name } }"""
294+ """{"data":{"__type":{"name":"User"}}}"""
295+
296+ it "returns null if no type with given name exists" do
297+ testQuery
298+ """{ __type(name: "NotFound") { name } }"""
299+ """{"data":{"__type":null}}"""
300+
301+ describe "__Type" do
302+ it "correctly returns data for object types" do
303+ testQuery
304+ """{ __type(name: "User") { name kind description } }"""
305+ """{"data":{"__type":{"name":"User","kind":"OBJECT","description":"A type for all users in the database"}}}"""
test/Language/Parser.purs+1−1
@@ -10,7 +10,7 @@ import Test.GraphQL.Language.Parser.Operation (parserOperationSpec)
1010import Test.GraphQL.Language.Parser.Value (valueSpec)
1111import Test.Spec (Spec, describe, it)
1212import Test.Spec.Assertions (shouldEqual)
13−import Text.Parsing.StringParser (runParser)
13+import StringParser (runParser)
1414
1515parserSpec :: Spec Unit
1616parserSpec =
test/Language/Parser/Field.purs+21−5
@@ -3,13 +3,13 @@ module Test.GraphQL.Language.Parser.Field where
33import Prelude
44
55import Data.Either (Either(..))
6−import Data.List (List(..))
6+import Data.List (List(..), singleton)
77import Data.Maybe (Maybe(..))
8−import GraphQL.Language.AST (ArgumentNode(..), DirectiveNode, NameNode(..), SelectionNode(..), SelectionSetNode, ValueNode(..))
8+import GraphQL.Language.AST (ArgumentNode(..), DirectiveNode, NameNode(..), SelectionNode(..), SelectionSetNode(..), SimpleNamedTypeNode(..), ValueNode(..))
99import GraphQL.Language.Parser (selection)
10+import StringParser (runParser)
1011import Test.Spec (Spec, describe, it)
1112import Test.Spec.Assertions (shouldEqual)
12−import Text.Parsing.StringParser (runParser)
1313
1414baseField ::
1515 { alias :: Maybe NameNode
@@ -27,14 +27,16 @@ baseField =
2727 }
2828
2929fieldSpec :: Spec Unit
30−fieldSpec =
30+fieldSpec = do
3131 describe "SelectionNode" do
3232 it "parses a simple field selection" $
3333 runParser selection " hello " `shouldEqual` Right (FieldNode baseField)
34+
3435 it "parses a field with an alias" $
3536 runParser selection " alias: hello "
3637 `shouldEqual`
3738 Right (FieldNode (baseField { alias = Just (NameNode { value: "alias" })}))
39+
3840 it "parses a field with arguments" do
3941 let args =
4042 (Cons
@@ -46,4 +48,18 @@ fieldSpec =
4648 )
4749 runParser selection "hello(arg1: 1, arg2: null)"
4850 `shouldEqual`
49− Right (FieldNode (baseField { arguments = args }))
51+ Right (FieldNode (baseField { arguments = args }))
52+
53+ it "parses a simple fragment spread" do
54+ runParser selection "...hello" `shouldEqual` Right (FragmentSpreadNode { name: NameNode { value: "hello" }, directives: Nil })
55+ runParser selection "...Hello" `shouldEqual` Right (FragmentSpreadNode { name: NameNode { value: "Hello" }, directives: Nil })
56+
57+ it "parses an inline fragment spread" do
58+ let result = runParser selection "...on Test { hello }"
59+ let expected = Right $
60+ InlineFragmentNode
61+ { typeCondition: SimpleNamedTypeNode { name: NameNode { value: "Test" } }
62+ , directives: Nil
63+ , selectionSet: SelectionSetNode { selections: singleton (FieldNode baseField) }
64+ }
65+ result `shouldEqual` expected
test/Language/Parser/Operation.purs+14−1
@@ -9,7 +9,7 @@ import GraphQL.Language.AST as AST
99import GraphQL.Language.Parser (document)
1010import Test.Spec (Spec, describe, it)
1111import Test.Spec.Assertions (shouldEqual)
12−import Text.Parsing.StringParser (runParser)
12+import StringParser (runParser)
1313
1414type OperationConfig =
1515 { name :: Maybe AST.NameNode
@@ -46,6 +46,10 @@ parserOperationSpec =
4646 let result = runParser document """{ hello }"""
4747 result `shouldEqual` Right (makeDocument identity)
4848
49+ it "parses a query without query keyword surrounded by whitespace" do
50+ let result = runParser document "\n \n\t{ hello } \n"
51+ result `shouldEqual` Right (makeDocument identity)
52+
4953 it "parses an anonymous query with query keyword" do
5054 let result = runParser document """query { hello }"""
5155 result `shouldEqual` Right (makeDocument identity)
@@ -54,11 +58,20 @@ parserOperationSpec =
5458 let result = runParser document """mutation { hello }"""
5559 result `shouldEqual` Right (makeDocument (_ { operation = AST.Mutation }))
5660
61+ it "parses an anonymous mutation surrounded by whitespace" do
62+ let result = runParser document " mutation { hello }\n"
63+ result `shouldEqual` Right (makeDocument (_ { operation = AST.Mutation }))
64+
5765 it "parses a named query with query keyword" do
5866 let result = runParser document """query MyQuery { hello }"""
5967 result `shouldEqual` Right
6068 (makeDocument (_ { name = Just $ AST.NameNode { value: "MyQuery" } }))
6169
70+ it "parses a named query with query keyword surrounded by whitespace" do
71+ let result = runParser document " \nquery MyQuery { hello } "
72+ result `shouldEqual` Right
73+ (makeDocument (_ { name = Just $ AST.NameNode { value: "MyQuery" } }))
74+
6275 it "parses a named mutation" do
6376 let result = runParser document """mutation MyMutation { hello }"""
6477 result `shouldEqual` Right
test/Language/Parser/Value.purs+7−7
@@ -8,7 +8,7 @@ import GraphQL.Language.AST (NameNode(..), ObjectFieldNode(..), ValueNode(..))
88import GraphQL.Language.Parser (value)
99import Test.Spec (Spec, describe, it)
1010import Test.Spec.Assertions (shouldEqual)
11−import Text.Parsing.StringParser (runParser)
11+import StringParser (runParser)
1212
1313valueSpec :: Spec Unit
1414valueSpec =
@@ -18,7 +18,7 @@ valueSpec =
1818
1919 it "parses a simple string" $
2020 runParser value "\"some string\"" `shouldEqual` Right (StringValueNode {block: false, value: "some string"})
21−
21+
2222 it "parses integer values" do
2323 runParser value "1234" `shouldEqual` Right (IntValueNode {value: "1234"})
2424 runParser value "0" `shouldEqual` Right (IntValueNode {value: "0"})
@@ -26,27 +26,27 @@ valueSpec =
2626 runParser value "-0" `shouldEqual` Right (IntValueNode {value: "-0"})
2727 isLeft (runParser value "02384") `shouldEqual` true
2828 isLeft (runParser value "-02384") `shouldEqual` true
29−
29+
3030 it "parses float values" do
3131 runParser value "234.23476" `shouldEqual` Right (FloatValueNode {value: "234.23476"})
3232 runParser value "-1.2" `shouldEqual` Right (FloatValueNode {value: "-1.2"})
3333 runParser value "1234E72" `shouldEqual` Right (FloatValueNode {value: "1234E72"})
3434 runParser value "434E-2" `shouldEqual` Right (FloatValueNode {value: "434E-2"})
3535 isLeft (runParser value "-023.000") `shouldEqual` true
36−
36+
3737 it "parses boolean values" do
3838 runParser value "true" `shouldEqual` Right (BooleanValueNode {value: true})
3939 runParser value "false" `shouldEqual` Right (BooleanValueNode {value: false})
40−
40+
4141 it "parses null values" do
4242 runParser value "null" `shouldEqual` Right NullValueNode
43−
43+
4444 it "parses enum values" do
4545 runParser value "SOME_ENUM" `shouldEqual` Right (EnumValueNode {name: NameNode {value: "SOME_ENUM"}})
4646 runParser value "uglyEnum" `shouldEqual` Right (EnumValueNode {name: NameNode {value: "uglyEnum"}})
4747 runParser value "lower" `shouldEqual` Right (EnumValueNode {name: NameNode {value: "lower"}})
4848 runParser value "WITH0" `shouldEqual` Right (EnumValueNode {name: NameNode {value: "WITH0"}})
49−
49+
5050 it "parses list values" do
5151 let listOf1 = IntValueNode {value: "1"} : Nil
5252 runParser value "[]" `shouldEqual` Right (ListValueNode {values: Nil})
test/Main.purs+4−3
@@ -5,8 +5,8 @@ import Prelude
55
66import Effect (Effect)
77import Effect.Aff (launchAff_)
8−import Main (readmeSpec)
9−import Test.GraphQL.Execution (executionSpec)
8+import Test.Async (asyncTest)
9+import Test.GraphQL.Execution (executionSpec, introspectionSpec)
1010import Test.GraphQL.Execution.Result (executionResultSpec)
1111import Test.GraphQL.Language.Parser (parserSpec)
1212import Test.Spec.Reporter (consoleReporter)
@@ -16,5 +16,6 @@ main :: Effect Unit
1616main = launchAff_ $ runSpec [consoleReporter] do
1717 parserSpec
1818 executionSpec
19+ introspectionSpec
1920 executionResultSpec
20− readmeSpec
21+ asyncTest
test/Readme.purs+23−25
@@ -1,42 +1,40 @@
1−module Main where
1+module Test.Readme where
22
33import Prelude
44
5−import Control.Monad.Error.Class (throwError)
5+import Control.Monad.Reader (ReaderT, runReaderT)
66import Data.Argonaut.Core (stringify)
7−import Data.Either (Either(..))
7+import Data.Map as Map
8+import Data.Maybe (Maybe(..))
89import Effect (Effect)
9−import Effect.Console as Console
10−import Effect.Exception (Error)
11−import GraphQL (graphql)
12−import GraphQL.Type ((!>), (.>), (:>))
13−import GraphQL.Type as GraphQL
14−import GraphQL.Type.Scalar as Scalar
10+import Effect.Class (liftEffect)
11+import GraphQL ((!>), (.>), (:>), (?>), graphql)
12+import GraphQL as GraphQL
1513import Test.Spec (Spec, describe, it)
1614import Test.Spec.Assertions (shouldEqual)
1715
18−main :: Effect Unit
19−main = case graphql schema "{ hello }" (pure unit) of
20− Left error -> Console.error $ show error
21− Right result -> Console.log $ stringify result
22−-- {"data":{"hello":"world"}}
16+-- main :: Effect Unit
17+-- main = do
18+-- result <- graphql schema """{ hello(name: "world") }""" Map.empty Nothing unit
19+-- Console.log $ stringify result -- {"data":{"hello":"world"}}
2320
24−schema :: GraphQL.Schema (Either Error) Unit
25−schema = GraphQL.Schema { query: queryType }
21+schema :: GraphQL.Schema (ReaderT String Effect) Unit
22+schema = GraphQL.Schema { query: queryType, mutation: Nothing }
2623
27−queryType :: GraphQL.ObjectType (Either Error) Unit
24+queryType :: GraphQL.ObjectType (ReaderT String Effect) Unit
2825queryType =
2926 GraphQL.objectType "Query"
30− .> "The root query type."
31− :> GraphQL.field "hello" Scalar.string
32− .> "A simple field that always returns \"world\"."
33− !> (\_ _ -> pure "world")
27+ :> "The root query type."
28+ .> GraphQL.field "hello" GraphQL.string
29+ ?> GraphQL.arg @"name" GraphQL.string
30+ :> "A simple field that returns a greeting."
31+ !> (\{ name } _ -> pure $ "Hello, " <> name <> "!")
3432
3533-- | A spec that tests that the example in the README actually works
3634readmeSpec :: Spec Unit
3735readmeSpec =
3836 describe "Readme" $
39− it "should execute the given query" $
40− case graphql schema "{ hello }" (pure unit) of
41− Left error -> throwError error
42− Right result -> stringify result `shouldEqual` """{"data":{"hello":"world"}}"""
37+ it "should execute the given query" $ liftEffect do
38+ let reader = graphql schema """{ hello(name: "Stranger") }""" Map.empty Nothing unit
39+ result <- runReaderT reader "Stranger"
40+ stringify result `shouldEqual` """{"data":{"hello":"Hello, Stranger!"}}"""