├── .editorconfig ├── .gitattributes ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── generated-docs └── md │ ├── Apiary.Client.md │ ├── Apiary.Media.md │ ├── Apiary.Method.md │ ├── Apiary.Request.md │ ├── Apiary.Response.md │ ├── Apiary.Route.md │ ├── Apiary.Status.md │ ├── Apiary.Types.md │ ├── Apiary.Url.md │ └── Apiary.md ├── package-lock.json ├── package.json ├── packages.dhall ├── spago.dhall └── src ├── Apiary.purs └── Apiary ├── Client.purs ├── Media.purs ├── Method.purs ├── Request.purs ├── Response.purs ├── Route.purs ├── Status.purs ├── Types.purs └── Url.purs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | end_of_line = lf 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components/ 2 | /node_modules/ 3 | /.pulp-cache/ 4 | /output/ 5 | /generated-docs/* 6 | !/generated-docs/md/ 7 | /generated-docs/md/* 8 | !/generated-docs/md/Apiary.* 9 | /.psc-package/ 10 | /.psc* 11 | /.purs* 12 | /.psa* 13 | /.spago 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "purescript.addNpmPath": true, 3 | "purescript.addPscPackageSources": true, 4 | "purescript.addSpagoSources": true, 5 | "purescript.editorMode": true, 6 | "purescript.buildCommand": "spago build -- --json-errors", 7 | "[purescript]": { 8 | "editor.formatOnSave": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | _ _ 3 | / \ _ __ (_) __ _ _ __ _ _ .' '. __ 4 | / _ \ | '_ \| |/ _` | '__| | | | . . . (__\_ 5 | / ___ \| |_) | | (_| | | | |_| | . . . -{{_(|8) 6 | /_/ \_\ .__/|_|\__,_|_| \__, | ' . . ' ' . . ' (__/ 7 | |_| |___/ 8 |9 | 10 | It's hard to be a busy little bee when working with unspec'ed APIs. This library is designed for the creation of type-level specs that can be queried against automatically! 11 | 12 | ### Example 13 | 14 | ```purescript 15 | type User 16 | = { id :: Int 17 | , name :: String 18 | , email :: String 19 | } 20 | 21 | type ListUsers 22 | = GET "/users" 23 | { query :: 24 | { sortBy :: UserSort 25 | , sortDir :: SortDir 26 | } 27 | , response :: 28 | { ok :: JSON (Array User) 29 | } 30 | } 31 | 32 | type CreateNewUser 33 | = POST "/users" 34 | { body :: JSON { name :: String, email :: String } 35 | , response :: 36 | { ok :: JSON User 37 | , badRequest :: JSON { errors :: Array { field :: String, message :: String } } 38 | } 39 | } 40 | 41 | listUsers params = 42 | Apiary.makeRequest (Route :: ListUsers) identity params none 43 | 44 | createNewUser body = 45 | Apiary.makeRequest (Route :: CreateNewUser) identity none body 46 | ``` 47 | 48 | This will give us inferred types equivalent to 49 | 50 | ```purescript 51 | listUsers :: 52 | { sortBy :: Maybe UserSort, sortDir :: Maybe SortDir } -> 53 | Aff (Either Apiary.Error (Variant ( ok :: Array User ))) 54 | 55 | createNewUser :: 56 | { name :: String, email :: String } -> 57 | Aff 58 | (Either Apiary.Error 59 | (Variant 60 | ( ok :: User 61 | , badRequest :: { errors :: Array { field :: String, message :: String } } 62 | ) 63 | ) 64 | ) 65 | ``` 66 | 67 | Here is an example with URL modification and JWT-based authorisation inspired by some production code: 68 | 69 | ```purescript 70 | makeSecureRequest :: 71 | forall m r route params body rep response. 72 | MonadAff m => 73 | MonadAsk { baseUrl :: String, token :: String | r } m => 74 | Apiary.BuildRequest route params body rep => 75 | Apiary.DecodeResponse rep response => 76 | route -> 77 | params -> 78 | body -> 79 | m (Either Apiary.Error response) 80 | makeSecureRequest route params body = do 81 | env <- ask 82 | liftAff $ mkRequest (addBaseUrl env.baseUrl <<< addToken env.token) 83 | where 84 | 85 | mkRequest modify = 86 | Apiary.makeRequest route modify params body 87 | 88 | addToken token request@{ headers } = 89 | request { headers = Object.insert "Authorization" ("Bearer " <> token) headers } 90 | 91 | addBaseUrl baseUrl request@{ url: URL url } = 92 | request { url = URL (baseUrl <> url) } 93 | 94 | type AppM = ReaderT { baseUrl :: String, token :: String } Aff 95 | 96 | listUsers :: 97 | { sortBy :: Maybe UserSort, sortDir :: Maybe SortDir } -> 98 | AppM (Either Apiary.Error (Variant ( ok :: Array User ))) 99 | listUsers params = 100 | makeSecureRequest (Route :: ListUsers) params unit 101 | ``` 102 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Client.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Client 2 | 3 | #### `makeRequest` 4 | 5 | ``` purescript 6 | makeRequest :: forall route params query body rep response. BuildRequest route params query body rep => DecodeResponse rep response => route -> (Request -> Request) -> params -> query -> body -> Aff (Either Error response) 7 | ``` 8 | 9 | #### `fetch` 10 | 11 | ``` purescript 12 | fetch :: Request -> ExceptT Error Aff Response 13 | ``` 14 | 15 | 16 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Media.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Media 2 | 3 | #### `MediaType` 4 | 5 | ``` purescript 6 | class MediaType rep where 7 | mediaType :: forall proxy. proxy rep -> Maybe MediaType 8 | ``` 9 | 10 | ##### Instances 11 | ``` purescript 12 | MediaType None 13 | MediaType String 14 | MediaType (JSON a) 15 | ``` 16 | 17 | #### `EncodeMedia` 18 | 19 | ``` purescript 20 | class EncodeMedia rep a | rep -> a where 21 | encodeMedia :: forall proxy. proxy rep -> a -> String 22 | ``` 23 | 24 | ##### Instances 25 | ``` purescript 26 | EncodeMedia None None 27 | EncodeMedia String String 28 | (WriteForeign a) => EncodeMedia (JSON a) a 29 | ``` 30 | 31 | #### `DecodeMedia` 32 | 33 | ``` purescript 34 | class DecodeMedia rep a | rep -> a where 35 | decodeMedia :: forall proxy. proxy rep -> String -> F a 36 | ``` 37 | 38 | ##### Instances 39 | ``` purescript 40 | DecodeMedia None None 41 | DecodeMedia String String 42 | (ReadForeign a) => DecodeMedia (JSON a) a 43 | ``` 44 | 45 | #### `JSON` 46 | 47 | ``` purescript 48 | data JSON a 49 | = JSON 50 | ``` 51 | 52 | ##### Instances 53 | ``` purescript 54 | MediaType (JSON a) 55 | (WriteForeign a) => EncodeMedia (JSON a) a 56 | (ReadForeign a) => DecodeMedia (JSON a) a 57 | ``` 58 | 59 | 60 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Method.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Method 2 | 3 | #### `RequestMethod` 4 | 5 | ``` purescript 6 | class RequestMethod (method :: Symbol) where 7 | toMethod :: SProxy method -> Method 8 | ``` 9 | 10 | ##### Instances 11 | ``` purescript 12 | RequestMethod "GET" 13 | RequestMethod "POST" 14 | RequestMethod "PUT" 15 | RequestMethod "PATCH" 16 | RequestMethod "DELETE" 17 | (Fail (Beside (Text "Unsupported request method: ") (Text method))) => RequestMethod method 18 | ``` 19 | 20 | 21 | ### Re-exported from Data.HTTP.Method: 22 | 23 | #### `Method` 24 | 25 | ``` purescript 26 | data Method 27 | = OPTIONS 28 | | GET 29 | | HEAD 30 | | POST 31 | | PUT 32 | | DELETE 33 | | TRACE 34 | | CONNECT 35 | | PROPFIND 36 | | PROPPATCH 37 | | MKCOL 38 | | COPY 39 | | MOVE 40 | | LOCK 41 | | UNLOCK 42 | | PATCH 43 | ``` 44 | 45 | ##### Instances 46 | ``` purescript 47 | Eq Method 48 | Ord Method 49 | Show Method 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Request.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Request 2 | 3 | #### `BuildRequest` 4 | 5 | ``` purescript 6 | class BuildRequest route params query body rep | route -> params query body rep where 7 | buildRequest :: route -> params -> query -> body -> Request 8 | ``` 9 | 10 | ##### Instances 11 | ``` purescript 12 | (PrepareSpec spec { body :: None, path :: params, query :: query, response :: response }, BuildUrl params query, DecodeResponse response response', IsSymbol path) => BuildRequest (Route "GET" path spec) params query None response 13 | (PrepareSpec spec { body :: body, path :: params, query :: query, response :: response }, RequestMethod method, BuildUrl params query, MediaType body, EncodeMedia body body', DecodeResponse response response', IsSymbol path) => BuildRequest (Route method path spec) params query body' response 14 | ``` 15 | 16 | #### `BuildUrl` 17 | 18 | ``` purescript 19 | class BuildUrl params query where 20 | buildUrl :: params -> query -> String -> String 21 | ``` 22 | 23 | ##### Instances 24 | ``` purescript 25 | (RowToList pathParams pathParamList, RowToList queryParams queryParamList, ReplacePathParams pathParams pathParamList, PrepareQueryParams queryParams queryParamList) => BuildUrl (Record pathParams) (Record queryParams) 26 | (BuildUrl path (Record ())) => BuildUrl path None 27 | (BuildUrl (Record ()) query) => BuildUrl None query 28 | BuildUrl None None 29 | ``` 30 | 31 | #### `PrepareQueryParams` 32 | 33 | ``` purescript 34 | class PrepareQueryParams (query :: # Type) (queryList :: RowList) | queryList -> query where 35 | prepareQueryParams :: forall proxy. proxy queryList -> Record query -> (forall h. ST h (STArray h { name :: String, value :: String })) -> Array { name :: String, value :: String } 36 | ``` 37 | 38 | ##### Instances 39 | ``` purescript 40 | PrepareQueryParams params Nil 41 | (IsSymbol name, EncodeParam value, Cons name (f value) query' query, Foldable f, PrepareQueryParams query queryTail) => PrepareQueryParams query (Cons name (f value) queryTail) 42 | (IsSymbol name, EncodeParam value, Cons name value query' query, PrepareQueryParams query queryTail) => PrepareQueryParams query (Cons name value queryTail) 43 | ``` 44 | 45 | #### `ReplacePathParams` 46 | 47 | ``` purescript 48 | class ReplacePathParams (params :: # Type) (paramList :: RowList) | paramList -> params where 49 | replacePathParams :: forall proxy. proxy paramList -> Record params -> String -> String 50 | ``` 51 | 52 | ##### Instances 53 | ``` purescript 54 | ReplacePathParams params Nil 55 | (IsSymbol name, EncodeParam value, Cons name value params' params, ReplacePathParams params paramTail) => ReplacePathParams params (Cons name value paramTail) 56 | ``` 57 | 58 | #### `buildPath` 59 | 60 | ``` purescript 61 | buildPath :: forall params paramList. RowToList params paramList => ReplacePathParams params paramList => Record params -> String -> String 62 | ``` 63 | 64 | #### `buildQuery` 65 | 66 | ``` purescript 67 | buildQuery :: forall query queryList. RowToList query queryList => PrepareQueryParams query queryList => Record query -> String 68 | ``` 69 | 70 | 71 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Response.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Response 2 | 3 | #### `DecodeResponse` 4 | 5 | ``` purescript 6 | class DecodeResponse rep response | rep -> response where 7 | decodeResponse :: forall proxy. proxy rep -> Response -> Except (Request -> Error) response 8 | ``` 9 | 10 | ##### Instances 11 | ``` purescript 12 | DecodeResponse None None 13 | DecodeResponse String String 14 | (RowToList responses responseList, DecodeResponseVariant result responseList) => DecodeResponse (Record responses) (Variant result) 15 | ``` 16 | 17 | #### `DecodeResponseVariant` 18 | 19 | ``` purescript 20 | class DecodeResponseVariant (response :: # Type) (responseList :: RowList) | responseList -> response where 21 | decodeResponseVariant :: forall proxy. proxy responseList -> Response -> Except (Request -> Error) (Variant response) 22 | ``` 23 | 24 | ##### Instances 25 | ``` purescript 26 | DecodeResponseVariant () Nil 27 | (IsSymbol status, ResponseStatus status, Cons status decoded variant' variant, DecodeResponseVariant variant' responseList, Union variant' a variant, DecodeMedia rep decoded) => DecodeResponseVariant variant (Cons status rep responseList) 28 | ``` 29 | 30 | #### `toStatus` 31 | 32 | ``` purescript 33 | toStatus :: forall response responseList. RowToList response responseList => ResponseVariantToStatus response responseList => Variant response -> Status 34 | ``` 35 | 36 | #### `ResponseVariantToStatus` 37 | 38 | ``` purescript 39 | class ResponseVariantToStatus (response :: # Type) (responseList :: RowList) | responseList -> response where 40 | responseVariantToStatus :: forall proxy. proxy responseList -> Variant response -> Status 41 | ``` 42 | 43 | ##### Instances 44 | ``` purescript 45 | ResponseVariantToStatus response Nil 46 | (IsSymbol status, ResponseStatus status, Cons status body response' response, ResponseVariantToStatus response responseList) => ResponseVariantToStatus response (Cons status body responseList) 47 | ``` 48 | 49 | 50 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Route.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Route 2 | 3 | #### `Route` 4 | 5 | ``` purescript 6 | data Route (method :: Symbol) (path :: Symbol) spec 7 | = Route 8 | ``` 9 | 10 | #### `SpecDefaults` 11 | 12 | ``` purescript 13 | type SpecDefaults = (body :: None, path :: None, query :: None, response :: None) 14 | ``` 15 | 16 | #### `PrepareSpec` 17 | 18 | ``` purescript 19 | class PrepareSpec spec prepared | spec -> prepared 20 | ``` 21 | 22 | ##### Instances 23 | ``` purescript 24 | (Union spec SpecDefaults specWithDefaults, Nub specWithDefaults prepared) => PrepareSpec (Record spec) (Record prepared) 25 | ``` 26 | 27 | #### `GET` 28 | 29 | ``` purescript 30 | type GET = Route "GET" 31 | ``` 32 | 33 | #### `PATCH` 34 | 35 | ``` purescript 36 | type PATCH = Route "PATCH" 37 | ``` 38 | 39 | #### `POST` 40 | 41 | ``` purescript 42 | type POST = Route "POST" 43 | ``` 44 | 45 | #### `PUT` 46 | 47 | ``` purescript 48 | type PUT = Route "PUT" 49 | ``` 50 | 51 | #### `DELETE` 52 | 53 | ``` purescript 54 | type DELETE = Route "DELETE" 55 | ``` 56 | 57 | 58 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Status.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Status 2 | 3 | #### `Status` 4 | 5 | ``` purescript 6 | newtype Status 7 | = Status { code :: Int, reason :: String } 8 | ``` 9 | 10 | ##### Instances 11 | ``` purescript 12 | Eq Status 13 | Show Status 14 | ``` 15 | 16 | #### `code` 17 | 18 | ``` purescript 19 | code :: Status -> Int 20 | ``` 21 | 22 | #### `reason` 23 | 24 | ``` purescript 25 | reason :: Status -> String 26 | ``` 27 | 28 | #### `toStatusCode` 29 | 30 | ``` purescript 31 | toStatusCode :: Status -> StatusCode 32 | ``` 33 | 34 | #### `status` 35 | 36 | ``` purescript 37 | status :: Int -> String -> Status 38 | ``` 39 | 40 | #### `ok` 41 | 42 | ``` purescript 43 | ok :: Status 44 | ``` 45 | 46 | #### `_ok` 47 | 48 | ``` purescript 49 | _ok :: SProxy "ok" 50 | ``` 51 | 52 | #### `created` 53 | 54 | ``` purescript 55 | created :: Status 56 | ``` 57 | 58 | #### `_created` 59 | 60 | ``` purescript 61 | _created :: SProxy "created" 62 | ``` 63 | 64 | #### `noContent` 65 | 66 | ``` purescript 67 | noContent :: Status 68 | ``` 69 | 70 | #### `_noContent` 71 | 72 | ``` purescript 73 | _noContent :: SProxy "noContent" 74 | ``` 75 | 76 | #### `notModified` 77 | 78 | ``` purescript 79 | notModified :: Status 80 | ``` 81 | 82 | #### `_notModified` 83 | 84 | ``` purescript 85 | _notModified :: SProxy "notModified" 86 | ``` 87 | 88 | #### `badRequest` 89 | 90 | ``` purescript 91 | badRequest :: Status 92 | ``` 93 | 94 | #### `_badRequest` 95 | 96 | ``` purescript 97 | _badRequest :: SProxy "badRequest" 98 | ``` 99 | 100 | #### `unauthorized` 101 | 102 | ``` purescript 103 | unauthorized :: Status 104 | ``` 105 | 106 | #### `_unauthorized` 107 | 108 | ``` purescript 109 | _unauthorized :: SProxy "unauthorized" 110 | ``` 111 | 112 | #### `forbidden` 113 | 114 | ``` purescript 115 | forbidden :: Status 116 | ``` 117 | 118 | #### `_forbidden` 119 | 120 | ``` purescript 121 | _forbidden :: SProxy "forbidden" 122 | ``` 123 | 124 | #### `notFound` 125 | 126 | ``` purescript 127 | notFound :: Status 128 | ``` 129 | 130 | #### `_notFound` 131 | 132 | ``` purescript 133 | _notFound :: SProxy "notFound" 134 | ``` 135 | 136 | #### `conflict` 137 | 138 | ``` purescript 139 | conflict :: Status 140 | ``` 141 | 142 | #### `_conflict` 143 | 144 | ``` purescript 145 | _conflict :: SProxy "conflict" 146 | ``` 147 | 148 | #### `unprocessableEntity` 149 | 150 | ``` purescript 151 | unprocessableEntity :: Status 152 | ``` 153 | 154 | #### `_unprocessableEntity` 155 | 156 | ``` purescript 157 | _unprocessableEntity :: SProxy "unprocessableEntity" 158 | ``` 159 | 160 | #### `maintenanceInProgress` 161 | 162 | ``` purescript 163 | maintenanceInProgress :: Status 164 | ``` 165 | 166 | #### `_maintenanceInProgress` 167 | 168 | ``` purescript 169 | _maintenanceInProgress :: SProxy "maintenanceInProgress" 170 | ``` 171 | 172 | #### `ResponseStatus` 173 | 174 | ``` purescript 175 | class ResponseStatus (status :: Symbol) where 176 | toStatus :: forall proxy. proxy status -> Status 177 | ``` 178 | 179 | ##### Instances 180 | ``` purescript 181 | ResponseStatus "ok" 182 | ResponseStatus "created" 183 | ResponseStatus "noContent" 184 | ResponseStatus "notModified" 185 | ResponseStatus "badRequest" 186 | ResponseStatus "unauthorized" 187 | ResponseStatus "forbidden" 188 | ResponseStatus "notFound" 189 | ResponseStatus "conflict" 190 | ResponseStatus "unprocessableEntity" 191 | (Fail (Beside (Text "Unsupported response status: ") (Text status))) => ResponseStatus status 192 | ``` 193 | 194 | 195 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Types.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Types 2 | 3 | #### `URL` 4 | 5 | ``` purescript 6 | type URL = String 7 | ``` 8 | 9 | #### `Request` 10 | 11 | ``` purescript 12 | type Request = { body :: String, headers :: Array RequestHeader, method :: Method, url :: URL } 13 | ``` 14 | 15 | #### `emptyRequest` 16 | 17 | ``` purescript 18 | emptyRequest :: Request 19 | ``` 20 | 21 | #### `Response` 22 | 23 | ``` purescript 24 | type Response = { body :: String, headers :: Array ResponseHeader, status :: StatusCode } 25 | ``` 26 | 27 | #### `Error` 28 | 29 | ``` purescript 30 | data Error 31 | = RuntimeError Error 32 | | DecodeError Request Response MultipleErrors 33 | | UnexpectedResponse Request Response 34 | ``` 35 | 36 | ##### Instances 37 | ``` purescript 38 | Show Error 39 | Semigroup Error 40 | ``` 41 | 42 | #### `None` 43 | 44 | ``` purescript 45 | data None :: Type 46 | ``` 47 | 48 | ##### Instances 49 | ``` purescript 50 | Show None 51 | Semigroup None 52 | Monoid None 53 | ``` 54 | 55 | #### `none` 56 | 57 | ``` purescript 58 | none :: None 59 | ``` 60 | 61 | 62 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.Url.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary.Url 2 | 3 | #### `EncodeParam` 4 | 5 | ``` purescript 6 | class EncodeParam a where 7 | encodeParam :: a -> String 8 | ``` 9 | 10 | ##### Instances 11 | ``` purescript 12 | EncodeParam String 13 | EncodeParam Boolean 14 | EncodeParam Int 15 | EncodeParam Number 16 | ``` 17 | 18 | #### `DecodeParam` 19 | 20 | ``` purescript 21 | class DecodeParam a where 22 | decodeParam :: String -> F a 23 | ``` 24 | 25 | ##### Instances 26 | ``` purescript 27 | DecodeParam String 28 | DecodeParam Boolean 29 | DecodeParam Int 30 | DecodeParam Number 31 | ``` 32 | 33 | 34 | -------------------------------------------------------------------------------- /generated-docs/md/Apiary.md: -------------------------------------------------------------------------------- 1 | ## Module Apiary 2 | 3 | 4 | ### Re-exported from Affjax.RequestHeader: 5 | 6 | #### `RequestHeader` 7 | 8 | ``` purescript 9 | data RequestHeader 10 | = Accept MediaType 11 | | ContentType MediaType 12 | | RequestHeader String String 13 | ``` 14 | 15 | ##### Instances 16 | ``` purescript 17 | Eq RequestHeader 18 | Ord RequestHeader 19 | Show RequestHeader 20 | ``` 21 | 22 | ### Re-exported from Apiary.Client: 23 | 24 | #### `makeRequest` 25 | 26 | ``` purescript 27 | makeRequest :: forall route params query body rep response. BuildRequest route params query body rep => DecodeResponse rep response => route -> (Request -> Request) -> params -> query -> body -> Aff (Either Error response) 28 | ``` 29 | 30 | #### `fetch` 31 | 32 | ``` purescript 33 | fetch :: Request -> ExceptT Error Aff Response 34 | ``` 35 | 36 | ### Re-exported from Apiary.Media: 37 | 38 | #### `JSON` 39 | 40 | ``` purescript 41 | data JSON a 42 | ``` 43 | 44 | ##### Instances 45 | ``` purescript 46 | MediaType (JSON a) 47 | (WriteForeign a) => EncodeMedia (JSON a) a 48 | (ReadForeign a) => DecodeMedia (JSON a) a 49 | ``` 50 | 51 | #### `DecodeMedia` 52 | 53 | ``` purescript 54 | class DecodeMedia rep a | rep -> a where 55 | decodeMedia :: forall proxy. proxy rep -> String -> F a 56 | ``` 57 | 58 | ##### Instances 59 | ``` purescript 60 | DecodeMedia None None 61 | DecodeMedia String String 62 | (ReadForeign a) => DecodeMedia (JSON a) a 63 | ``` 64 | 65 | #### `EncodeMedia` 66 | 67 | ``` purescript 68 | class EncodeMedia rep a | rep -> a where 69 | encodeMedia :: forall proxy. proxy rep -> a -> String 70 | ``` 71 | 72 | ##### Instances 73 | ``` purescript 74 | EncodeMedia None None 75 | EncodeMedia String String 76 | (WriteForeign a) => EncodeMedia (JSON a) a 77 | ``` 78 | 79 | #### `MediaType` 80 | 81 | ``` purescript 82 | class MediaType rep where 83 | mediaType :: forall proxy. proxy rep -> Maybe MediaType 84 | ``` 85 | 86 | ##### Instances 87 | ``` purescript 88 | MediaType None 89 | MediaType String 90 | MediaType (JSON a) 91 | ``` 92 | 93 | ### Re-exported from Apiary.Request: 94 | 95 | #### `BuildRequest` 96 | 97 | ``` purescript 98 | class BuildRequest route params query body rep | route -> params query body rep where 99 | buildRequest :: route -> params -> query -> body -> Request 100 | ``` 101 | 102 | ##### Instances 103 | ``` purescript 104 | (PrepareSpec spec { body :: None, path :: params, query :: query, response :: response }, BuildUrl params query, DecodeResponse response response', IsSymbol path) => BuildRequest (Route "GET" path spec) params query None response 105 | (PrepareSpec spec { body :: body, path :: params, query :: query, response :: response }, RequestMethod method, BuildUrl params query, MediaType body, EncodeMedia body body', DecodeResponse response response', IsSymbol path) => BuildRequest (Route method path spec) params query body' response 106 | ``` 107 | 108 | #### `BuildUrl` 109 | 110 | ``` purescript 111 | class BuildUrl params query where 112 | buildUrl :: params -> query -> String -> String 113 | ``` 114 | 115 | ##### Instances 116 | ``` purescript 117 | (RowToList pathParams pathParamList, RowToList queryParams queryParamList, ReplacePathParams pathParams pathParamList, PrepareQueryParams queryParams queryParamList) => BuildUrl (Record pathParams) (Record queryParams) 118 | (BuildUrl path (Record ())) => BuildUrl path None 119 | (BuildUrl (Record ()) query) => BuildUrl None query 120 | BuildUrl None None 121 | ``` 122 | 123 | #### `PrepareQueryParams` 124 | 125 | ``` purescript 126 | class PrepareQueryParams (query :: # Type) (queryList :: RowList) | queryList -> query 127 | ``` 128 | 129 | ##### Instances 130 | ``` purescript 131 | PrepareQueryParams params Nil 132 | (IsSymbol name, EncodeParam value, Cons name (f value) query' query, Foldable f, PrepareQueryParams query queryTail) => PrepareQueryParams query (Cons name (f value) queryTail) 133 | (IsSymbol name, EncodeParam value, Cons name value query' query, PrepareQueryParams query queryTail) => PrepareQueryParams query (Cons name value queryTail) 134 | ``` 135 | 136 | #### `ReplacePathParams` 137 | 138 | ``` purescript 139 | class ReplacePathParams (params :: # Type) (paramList :: RowList) | paramList -> params 140 | ``` 141 | 142 | ##### Instances 143 | ``` purescript 144 | ReplacePathParams params Nil 145 | (IsSymbol name, EncodeParam value, Cons name value params' params, ReplacePathParams params paramTail) => ReplacePathParams params (Cons name value paramTail) 146 | ``` 147 | 148 | #### `buildQuery` 149 | 150 | ``` purescript 151 | buildQuery :: forall query queryList. RowToList query queryList => PrepareQueryParams query queryList => Record query -> String 152 | ``` 153 | 154 | #### `buildPath` 155 | 156 | ``` purescript 157 | buildPath :: forall params paramList. RowToList params paramList => ReplacePathParams params paramList => Record params -> String -> String 158 | ``` 159 | 160 | ### Re-exported from Apiary.Response: 161 | 162 | #### `DecodeResponse` 163 | 164 | ``` purescript 165 | class DecodeResponse rep response | rep -> response where 166 | decodeResponse :: forall proxy. proxy rep -> Response -> Except (Request -> Error) response 167 | ``` 168 | 169 | ##### Instances 170 | ``` purescript 171 | DecodeResponse None None 172 | DecodeResponse String String 173 | (RowToList responses responseList, DecodeResponseVariant result responseList) => DecodeResponse (Record responses) (Variant result) 174 | ``` 175 | 176 | #### `toStatus` 177 | 178 | ``` purescript 179 | toStatus :: forall response responseList. RowToList response responseList => ResponseVariantToStatus response responseList => Variant response -> Status 180 | ``` 181 | 182 | ### Re-exported from Apiary.Route: 183 | 184 | #### `Route` 185 | 186 | ``` purescript 187 | data Route (method :: Symbol) (path :: Symbol) spec 188 | = Route 189 | ``` 190 | 191 | #### `PUT` 192 | 193 | ``` purescript 194 | type PUT = Route "PUT" 195 | ``` 196 | 197 | #### `POST` 198 | 199 | ``` purescript 200 | type POST = Route "POST" 201 | ``` 202 | 203 | #### `PATCH` 204 | 205 | ``` purescript 206 | type PATCH = Route "PATCH" 207 | ``` 208 | 209 | #### `GET` 210 | 211 | ``` purescript 212 | type GET = Route "GET" 213 | ``` 214 | 215 | #### `DELETE` 216 | 217 | ``` purescript 218 | type DELETE = Route "DELETE" 219 | ``` 220 | 221 | ### Re-exported from Apiary.Types: 222 | 223 | #### `URL` 224 | 225 | ``` purescript 226 | type URL = String 227 | ``` 228 | 229 | #### `Response` 230 | 231 | ``` purescript 232 | type Response = { body :: String, headers :: Array ResponseHeader, status :: StatusCode } 233 | ``` 234 | 235 | #### `Request` 236 | 237 | ``` purescript 238 | type Request = { body :: String, headers :: Array RequestHeader, method :: Method, url :: URL } 239 | ``` 240 | 241 | #### `None` 242 | 243 | ``` purescript 244 | data None :: Type 245 | ``` 246 | 247 | ##### Instances 248 | ``` purescript 249 | Show None 250 | Semigroup None 251 | Monoid None 252 | ``` 253 | 254 | #### `Error` 255 | 256 | ``` purescript 257 | data Error 258 | = RuntimeError Error 259 | | DecodeError Request Response MultipleErrors 260 | | UnexpectedResponse Request Response 261 | ``` 262 | 263 | ##### Instances 264 | ``` purescript 265 | Show Error 266 | Semigroup Error 267 | ``` 268 | 269 | #### `none` 270 | 271 | ``` purescript 272 | none :: None 273 | ``` 274 | 275 | #### `emptyRequest` 276 | 277 | ``` purescript 278 | emptyRequest :: Request 279 | ``` 280 | 281 | ### Re-exported from Apiary.Url: 282 | 283 | #### `DecodeParam` 284 | 285 | ``` purescript 286 | class DecodeParam a where 287 | decodeParam :: String -> F a 288 | ``` 289 | 290 | ##### Instances 291 | ``` purescript 292 | DecodeParam String 293 | DecodeParam Boolean 294 | DecodeParam Int 295 | DecodeParam Number 296 | ``` 297 | 298 | #### `EncodeParam` 299 | 300 | ``` purescript 301 | class EncodeParam a where 302 | encodeParam :: a -> String 303 | ``` 304 | 305 | ##### Instances 306 | ``` purescript 307 | EncodeParam String 308 | EncodeParam Boolean 309 | EncodeParam Int 310 | EncodeParam Number 311 | ``` 312 | 313 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-apiary", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ajv": { 8 | "version": "6.12.5", 9 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", 10 | "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", 11 | "dev": true, 12 | "requires": { 13 | "fast-deep-equal": "^3.1.1", 14 | "fast-json-stable-stringify": "^2.0.0", 15 | "json-schema-traverse": "^0.4.1", 16 | "uri-js": "^4.2.2" 17 | } 18 | }, 19 | "ansi-escapes": { 20 | "version": "3.2.0", 21 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", 22 | "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", 23 | "dev": true 24 | }, 25 | "ansi-regex": { 26 | "version": "4.1.0", 27 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 28 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 29 | "dev": true 30 | }, 31 | "ansi-styles": { 32 | "version": "3.2.1", 33 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 34 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 35 | "dev": true, 36 | "requires": { 37 | "color-convert": "^1.9.0" 38 | } 39 | }, 40 | "aproba": { 41 | "version": "1.2.0", 42 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", 43 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", 44 | "dev": true 45 | }, 46 | "arch": { 47 | "version": "2.1.2", 48 | "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz", 49 | "integrity": "sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ==", 50 | "dev": true 51 | }, 52 | "asn1": { 53 | "version": "0.2.4", 54 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 55 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 56 | "dev": true, 57 | "requires": { 58 | "safer-buffer": "~2.1.0" 59 | } 60 | }, 61 | "assert-plus": { 62 | "version": "1.0.0", 63 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 64 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 65 | "dev": true 66 | }, 67 | "asynckit": { 68 | "version": "0.4.0", 69 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 70 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 71 | "dev": true 72 | }, 73 | "aws-sign2": { 74 | "version": "0.7.0", 75 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 76 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", 77 | "dev": true 78 | }, 79 | "aws4": { 80 | "version": "1.10.1", 81 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", 82 | "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==", 83 | "dev": true 84 | }, 85 | "balanced-match": { 86 | "version": "1.0.0", 87 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 88 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 89 | "dev": true 90 | }, 91 | "bcrypt-pbkdf": { 92 | "version": "1.0.2", 93 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 94 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 95 | "dev": true, 96 | "requires": { 97 | "tweetnacl": "^0.14.3" 98 | } 99 | }, 100 | "bluebird": { 101 | "version": "3.7.2", 102 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 103 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", 104 | "dev": true 105 | }, 106 | "brace-expansion": { 107 | "version": "1.1.11", 108 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 109 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 110 | "dev": true, 111 | "requires": { 112 | "balanced-match": "^1.0.0", 113 | "concat-map": "0.0.1" 114 | } 115 | }, 116 | "buffer-from": { 117 | "version": "1.1.1", 118 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 119 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 120 | "dev": true 121 | }, 122 | "byline": { 123 | "version": "5.0.0", 124 | "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", 125 | "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=", 126 | "dev": true 127 | }, 128 | "cacache": { 129 | "version": "11.3.3", 130 | "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", 131 | "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", 132 | "dev": true, 133 | "requires": { 134 | "bluebird": "^3.5.5", 135 | "chownr": "^1.1.1", 136 | "figgy-pudding": "^3.5.1", 137 | "glob": "^7.1.4", 138 | "graceful-fs": "^4.1.15", 139 | "lru-cache": "^5.1.1", 140 | "mississippi": "^3.0.0", 141 | "mkdirp": "^0.5.1", 142 | "move-concurrently": "^1.0.1", 143 | "promise-inflight": "^1.0.1", 144 | "rimraf": "^2.6.3", 145 | "ssri": "^6.0.1", 146 | "unique-filename": "^1.1.1", 147 | "y18n": "^4.0.0" 148 | } 149 | }, 150 | "caseless": { 151 | "version": "0.12.0", 152 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 153 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", 154 | "dev": true 155 | }, 156 | "chalk": { 157 | "version": "2.4.2", 158 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 159 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 160 | "dev": true, 161 | "requires": { 162 | "ansi-styles": "^3.2.1", 163 | "escape-string-regexp": "^1.0.5", 164 | "supports-color": "^5.3.0" 165 | } 166 | }, 167 | "chownr": { 168 | "version": "1.1.4", 169 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 170 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", 171 | "dev": true 172 | }, 173 | "cli-cursor": { 174 | "version": "2.1.0", 175 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 176 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 177 | "dev": true, 178 | "requires": { 179 | "restore-cursor": "^2.0.0" 180 | } 181 | }, 182 | "color-convert": { 183 | "version": "1.9.3", 184 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 185 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 186 | "dev": true, 187 | "requires": { 188 | "color-name": "1.1.3" 189 | } 190 | }, 191 | "color-name": { 192 | "version": "1.1.3", 193 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 194 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 195 | "dev": true 196 | }, 197 | "combined-stream": { 198 | "version": "1.0.8", 199 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 200 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 201 | "dev": true, 202 | "requires": { 203 | "delayed-stream": "~1.0.0" 204 | } 205 | }, 206 | "concat-map": { 207 | "version": "0.0.1", 208 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 209 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 210 | "dev": true 211 | }, 212 | "concat-stream": { 213 | "version": "1.6.2", 214 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", 215 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", 216 | "dev": true, 217 | "requires": { 218 | "buffer-from": "^1.0.0", 219 | "inherits": "^2.0.3", 220 | "readable-stream": "^2.2.2", 221 | "typedarray": "^0.0.6" 222 | } 223 | }, 224 | "copy-concurrently": { 225 | "version": "1.0.5", 226 | "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", 227 | "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", 228 | "dev": true, 229 | "requires": { 230 | "aproba": "^1.1.1", 231 | "fs-write-stream-atomic": "^1.0.8", 232 | "iferr": "^0.1.5", 233 | "mkdirp": "^0.5.1", 234 | "rimraf": "^2.5.4", 235 | "run-queue": "^1.0.0" 236 | } 237 | }, 238 | "core-util-is": { 239 | "version": "1.0.2", 240 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 241 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 242 | "dev": true 243 | }, 244 | "cross-spawn": { 245 | "version": "7.0.3", 246 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 247 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 248 | "dev": true, 249 | "requires": { 250 | "path-key": "^3.1.0", 251 | "shebang-command": "^2.0.0", 252 | "which": "^2.0.1" 253 | }, 254 | "dependencies": { 255 | "which": { 256 | "version": "2.0.2", 257 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 258 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 259 | "dev": true, 260 | "requires": { 261 | "isexe": "^2.0.0" 262 | } 263 | } 264 | } 265 | }, 266 | "cyclist": { 267 | "version": "1.0.1", 268 | "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", 269 | "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", 270 | "dev": true 271 | }, 272 | "dashdash": { 273 | "version": "1.14.1", 274 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 275 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 276 | "dev": true, 277 | "requires": { 278 | "assert-plus": "^1.0.0" 279 | } 280 | }, 281 | "delayed-stream": { 282 | "version": "1.0.0", 283 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 284 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 285 | "dev": true 286 | }, 287 | "duplexify": { 288 | "version": "3.7.1", 289 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", 290 | "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", 291 | "dev": true, 292 | "requires": { 293 | "end-of-stream": "^1.0.0", 294 | "inherits": "^2.0.1", 295 | "readable-stream": "^2.0.0", 296 | "stream-shift": "^1.0.0" 297 | } 298 | }, 299 | "ecc-jsbn": { 300 | "version": "0.1.2", 301 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 302 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 303 | "dev": true, 304 | "requires": { 305 | "jsbn": "~0.1.0", 306 | "safer-buffer": "^2.1.0" 307 | } 308 | }, 309 | "emoji-regex": { 310 | "version": "7.0.3", 311 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 312 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 313 | "dev": true 314 | }, 315 | "end-of-stream": { 316 | "version": "1.4.4", 317 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 318 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 319 | "dev": true, 320 | "requires": { 321 | "once": "^1.4.0" 322 | } 323 | }, 324 | "env-paths": { 325 | "version": "2.2.0", 326 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", 327 | "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==", 328 | "dev": true 329 | }, 330 | "escape-string-regexp": { 331 | "version": "1.0.5", 332 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 333 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 334 | "dev": true 335 | }, 336 | "execa": { 337 | "version": "2.1.0", 338 | "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", 339 | "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", 340 | "dev": true, 341 | "requires": { 342 | "cross-spawn": "^7.0.0", 343 | "get-stream": "^5.0.0", 344 | "is-stream": "^2.0.0", 345 | "merge-stream": "^2.0.0", 346 | "npm-run-path": "^3.0.0", 347 | "onetime": "^5.1.0", 348 | "p-finally": "^2.0.0", 349 | "signal-exit": "^3.0.2", 350 | "strip-final-newline": "^2.0.0" 351 | } 352 | }, 353 | "extend": { 354 | "version": "3.0.2", 355 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 356 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", 357 | "dev": true 358 | }, 359 | "extsprintf": { 360 | "version": "1.3.0", 361 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 362 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", 363 | "dev": true 364 | }, 365 | "fast-deep-equal": { 366 | "version": "3.1.3", 367 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 368 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 369 | "dev": true 370 | }, 371 | "fast-json-stable-stringify": { 372 | "version": "2.1.0", 373 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 374 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 375 | "dev": true 376 | }, 377 | "figgy-pudding": { 378 | "version": "3.5.2", 379 | "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", 380 | "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", 381 | "dev": true 382 | }, 383 | "filesize": { 384 | "version": "4.2.1", 385 | "resolved": "https://registry.npmjs.org/filesize/-/filesize-4.2.1.tgz", 386 | "integrity": "sha512-bP82Hi8VRZX/TUBKfE24iiUGsB/sfm2WUrwTQyAzQrhO3V9IhcBBNBXMyzLY5orACxRyYJ3d2HeRVX+eFv4lmA==", 387 | "dev": true 388 | }, 389 | "flush-write-stream": { 390 | "version": "1.1.1", 391 | "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", 392 | "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", 393 | "dev": true, 394 | "requires": { 395 | "inherits": "^2.0.3", 396 | "readable-stream": "^2.3.6" 397 | } 398 | }, 399 | "forever-agent": { 400 | "version": "0.6.1", 401 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 402 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", 403 | "dev": true 404 | }, 405 | "form-data": { 406 | "version": "2.3.3", 407 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 408 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 409 | "dev": true, 410 | "requires": { 411 | "asynckit": "^0.4.0", 412 | "combined-stream": "^1.0.6", 413 | "mime-types": "^2.1.12" 414 | } 415 | }, 416 | "from2": { 417 | "version": "2.3.0", 418 | "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", 419 | "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", 420 | "dev": true, 421 | "requires": { 422 | "inherits": "^2.0.1", 423 | "readable-stream": "^2.0.0" 424 | } 425 | }, 426 | "fs-minipass": { 427 | "version": "1.2.7", 428 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", 429 | "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", 430 | "dev": true, 431 | "requires": { 432 | "minipass": "^2.6.0" 433 | } 434 | }, 435 | "fs-write-stream-atomic": { 436 | "version": "1.0.10", 437 | "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", 438 | "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", 439 | "dev": true, 440 | "requires": { 441 | "graceful-fs": "^4.1.2", 442 | "iferr": "^0.1.5", 443 | "imurmurhash": "^0.1.4", 444 | "readable-stream": "1 || 2" 445 | } 446 | }, 447 | "fs.realpath": { 448 | "version": "1.0.0", 449 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 450 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 451 | "dev": true 452 | }, 453 | "get-stream": { 454 | "version": "5.2.0", 455 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 456 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 457 | "dev": true, 458 | "requires": { 459 | "pump": "^3.0.0" 460 | } 461 | }, 462 | "getpass": { 463 | "version": "0.1.7", 464 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 465 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 466 | "dev": true, 467 | "requires": { 468 | "assert-plus": "^1.0.0" 469 | } 470 | }, 471 | "glob": { 472 | "version": "7.1.6", 473 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 474 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 475 | "dev": true, 476 | "requires": { 477 | "fs.realpath": "^1.0.0", 478 | "inflight": "^1.0.4", 479 | "inherits": "2", 480 | "minimatch": "^3.0.4", 481 | "once": "^1.3.0", 482 | "path-is-absolute": "^1.0.0" 483 | } 484 | }, 485 | "graceful-fs": { 486 | "version": "4.2.4", 487 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", 488 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", 489 | "dev": true 490 | }, 491 | "har-schema": { 492 | "version": "2.0.0", 493 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 494 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", 495 | "dev": true 496 | }, 497 | "har-validator": { 498 | "version": "5.1.5", 499 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", 500 | "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", 501 | "dev": true, 502 | "requires": { 503 | "ajv": "^6.12.3", 504 | "har-schema": "^2.0.0" 505 | } 506 | }, 507 | "has-flag": { 508 | "version": "3.0.0", 509 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 510 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 511 | "dev": true 512 | }, 513 | "http-signature": { 514 | "version": "1.2.0", 515 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 516 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 517 | "dev": true, 518 | "requires": { 519 | "assert-plus": "^1.0.0", 520 | "jsprim": "^1.2.2", 521 | "sshpk": "^1.7.0" 522 | } 523 | }, 524 | "iferr": { 525 | "version": "0.1.5", 526 | "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", 527 | "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", 528 | "dev": true 529 | }, 530 | "imurmurhash": { 531 | "version": "0.1.4", 532 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 533 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 534 | "dev": true 535 | }, 536 | "inflight": { 537 | "version": "1.0.6", 538 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 539 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 540 | "dev": true, 541 | "requires": { 542 | "once": "^1.3.0", 543 | "wrappy": "1" 544 | } 545 | }, 546 | "inherits": { 547 | "version": "2.0.4", 548 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 549 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 550 | "dev": true 551 | }, 552 | "is-fullwidth-code-point": { 553 | "version": "2.0.0", 554 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 555 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 556 | "dev": true 557 | }, 558 | "is-plain-obj": { 559 | "version": "2.1.0", 560 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 561 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 562 | "dev": true 563 | }, 564 | "is-stream": { 565 | "version": "2.0.0", 566 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", 567 | "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", 568 | "dev": true 569 | }, 570 | "is-typedarray": { 571 | "version": "1.0.0", 572 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 573 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", 574 | "dev": true 575 | }, 576 | "isarray": { 577 | "version": "1.0.0", 578 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 579 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 580 | "dev": true 581 | }, 582 | "isexe": { 583 | "version": "2.0.0", 584 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 585 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 586 | "dev": true 587 | }, 588 | "isstream": { 589 | "version": "0.1.2", 590 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 591 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", 592 | "dev": true 593 | }, 594 | "jsbn": { 595 | "version": "0.1.1", 596 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 597 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", 598 | "dev": true 599 | }, 600 | "json-schema": { 601 | "version": "0.2.3", 602 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 603 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", 604 | "dev": true 605 | }, 606 | "json-schema-traverse": { 607 | "version": "0.4.1", 608 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 609 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 610 | "dev": true 611 | }, 612 | "json-stringify-safe": { 613 | "version": "5.0.1", 614 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 615 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", 616 | "dev": true 617 | }, 618 | "jsprim": { 619 | "version": "1.4.1", 620 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 621 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 622 | "dev": true, 623 | "requires": { 624 | "assert-plus": "1.0.0", 625 | "extsprintf": "1.3.0", 626 | "json-schema": "0.2.3", 627 | "verror": "1.10.0" 628 | } 629 | }, 630 | "log-symbols": { 631 | "version": "3.0.0", 632 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", 633 | "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", 634 | "dev": true, 635 | "requires": { 636 | "chalk": "^2.4.2" 637 | } 638 | }, 639 | "log-update": { 640 | "version": "3.4.0", 641 | "resolved": "https://registry.npmjs.org/log-update/-/log-update-3.4.0.tgz", 642 | "integrity": "sha512-ILKe88NeMt4gmDvk/eb615U/IVn7K9KWGkoYbdatQ69Z65nj1ZzjM6fHXfcs0Uge+e+EGnMW7DY4T9yko8vWFg==", 643 | "dev": true, 644 | "requires": { 645 | "ansi-escapes": "^3.2.0", 646 | "cli-cursor": "^2.1.0", 647 | "wrap-ansi": "^5.0.0" 648 | } 649 | }, 650 | "lru-cache": { 651 | "version": "5.1.1", 652 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 653 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 654 | "dev": true, 655 | "requires": { 656 | "yallist": "^3.0.2" 657 | } 658 | }, 659 | "merge-stream": { 660 | "version": "2.0.0", 661 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 662 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", 663 | "dev": true 664 | }, 665 | "mime-db": { 666 | "version": "1.44.0", 667 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 668 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", 669 | "dev": true 670 | }, 671 | "mime-types": { 672 | "version": "2.1.27", 673 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 674 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 675 | "dev": true, 676 | "requires": { 677 | "mime-db": "1.44.0" 678 | } 679 | }, 680 | "mimic-fn": { 681 | "version": "2.1.0", 682 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 683 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", 684 | "dev": true 685 | }, 686 | "minimatch": { 687 | "version": "3.0.4", 688 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 689 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 690 | "dev": true, 691 | "requires": { 692 | "brace-expansion": "^1.1.7" 693 | } 694 | }, 695 | "minimist": { 696 | "version": "1.2.5", 697 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 698 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 699 | "dev": true 700 | }, 701 | "minipass": { 702 | "version": "2.9.0", 703 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", 704 | "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", 705 | "dev": true, 706 | "requires": { 707 | "safe-buffer": "^5.1.2", 708 | "yallist": "^3.0.0" 709 | } 710 | }, 711 | "minizlib": { 712 | "version": "1.3.3", 713 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", 714 | "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", 715 | "dev": true, 716 | "requires": { 717 | "minipass": "^2.9.0" 718 | } 719 | }, 720 | "mississippi": { 721 | "version": "3.0.0", 722 | "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", 723 | "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", 724 | "dev": true, 725 | "requires": { 726 | "concat-stream": "^1.5.0", 727 | "duplexify": "^3.4.2", 728 | "end-of-stream": "^1.1.0", 729 | "flush-write-stream": "^1.0.0", 730 | "from2": "^2.1.0", 731 | "parallel-transform": "^1.1.0", 732 | "pump": "^3.0.0", 733 | "pumpify": "^1.3.3", 734 | "stream-each": "^1.1.0", 735 | "through2": "^2.0.0" 736 | } 737 | }, 738 | "mkdirp": { 739 | "version": "0.5.5", 740 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 741 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 742 | "dev": true, 743 | "requires": { 744 | "minimist": "^1.2.5" 745 | } 746 | }, 747 | "move-concurrently": { 748 | "version": "1.0.1", 749 | "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", 750 | "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", 751 | "dev": true, 752 | "requires": { 753 | "aproba": "^1.1.1", 754 | "copy-concurrently": "^1.0.0", 755 | "fs-write-stream-atomic": "^1.0.8", 756 | "mkdirp": "^0.5.1", 757 | "rimraf": "^2.5.4", 758 | "run-queue": "^1.0.3" 759 | } 760 | }, 761 | "ms": { 762 | "version": "2.1.2", 763 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 764 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 765 | "dev": true 766 | }, 767 | "npm-run-path": { 768 | "version": "3.1.0", 769 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", 770 | "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", 771 | "dev": true, 772 | "requires": { 773 | "path-key": "^3.0.0" 774 | } 775 | }, 776 | "oauth-sign": { 777 | "version": "0.9.0", 778 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 779 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", 780 | "dev": true 781 | }, 782 | "once": { 783 | "version": "1.4.0", 784 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 785 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 786 | "dev": true, 787 | "requires": { 788 | "wrappy": "1" 789 | } 790 | }, 791 | "onetime": { 792 | "version": "5.1.2", 793 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 794 | "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 795 | "dev": true, 796 | "requires": { 797 | "mimic-fn": "^2.1.0" 798 | } 799 | }, 800 | "p-finally": { 801 | "version": "2.0.1", 802 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", 803 | "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", 804 | "dev": true 805 | }, 806 | "parallel-transform": { 807 | "version": "1.2.0", 808 | "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", 809 | "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", 810 | "dev": true, 811 | "requires": { 812 | "cyclist": "^1.0.1", 813 | "inherits": "^2.0.3", 814 | "readable-stream": "^2.1.5" 815 | } 816 | }, 817 | "path-is-absolute": { 818 | "version": "1.0.1", 819 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 820 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 821 | "dev": true 822 | }, 823 | "path-key": { 824 | "version": "3.1.1", 825 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 826 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 827 | "dev": true 828 | }, 829 | "performance-now": { 830 | "version": "2.1.0", 831 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 832 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", 833 | "dev": true 834 | }, 835 | "process-nextick-args": { 836 | "version": "2.0.1", 837 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 838 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 839 | "dev": true 840 | }, 841 | "promise-inflight": { 842 | "version": "1.0.1", 843 | "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", 844 | "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", 845 | "dev": true 846 | }, 847 | "psl": { 848 | "version": "1.8.0", 849 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", 850 | "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", 851 | "dev": true 852 | }, 853 | "pump": { 854 | "version": "3.0.0", 855 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 856 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 857 | "dev": true, 858 | "requires": { 859 | "end-of-stream": "^1.1.0", 860 | "once": "^1.3.1" 861 | } 862 | }, 863 | "pumpify": { 864 | "version": "1.5.1", 865 | "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", 866 | "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", 867 | "dev": true, 868 | "requires": { 869 | "duplexify": "^3.6.0", 870 | "inherits": "^2.0.3", 871 | "pump": "^2.0.0" 872 | }, 873 | "dependencies": { 874 | "pump": { 875 | "version": "2.0.1", 876 | "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", 877 | "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", 878 | "dev": true, 879 | "requires": { 880 | "end-of-stream": "^1.1.0", 881 | "once": "^1.3.1" 882 | } 883 | } 884 | } 885 | }, 886 | "punycode": { 887 | "version": "2.1.1", 888 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 889 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 890 | "dev": true 891 | }, 892 | "purescript": { 893 | "version": "0.13.8", 894 | "resolved": "https://registry.npmjs.org/purescript/-/purescript-0.13.8.tgz", 895 | "integrity": "sha512-1ZyVEVFLgcEcjPXxJYeVEyYn66DF2DnOLTWzo/K/MrQUF2chdLSyZ8sJpcarWyrz2HxXaubYceYbo5KexKzynA==", 896 | "dev": true, 897 | "requires": { 898 | "purescript-installer": "^0.2.0" 899 | } 900 | }, 901 | "purescript-installer": { 902 | "version": "0.2.5", 903 | "resolved": "https://registry.npmjs.org/purescript-installer/-/purescript-installer-0.2.5.tgz", 904 | "integrity": "sha512-fQAWWP5a7scuchXecjpU4r4KEgSPuS6bBnaP01k9f71qqD28HaJ2m4PXHFkhkR4oATAxTPIGCtmTwtVoiBOHog==", 905 | "dev": true, 906 | "requires": { 907 | "arch": "^2.1.1", 908 | "byline": "^5.0.0", 909 | "cacache": "^11.3.2", 910 | "chalk": "^2.4.2", 911 | "env-paths": "^2.2.0", 912 | "execa": "^2.0.3", 913 | "filesize": "^4.1.2", 914 | "is-plain-obj": "^2.0.0", 915 | "log-symbols": "^3.0.0", 916 | "log-update": "^3.2.0", 917 | "minimist": "^1.2.0", 918 | "mkdirp": "^0.5.1", 919 | "ms": "^2.1.2", 920 | "once": "^1.4.0", 921 | "pump": "^3.0.0", 922 | "request": "^2.88.0", 923 | "rimraf": "^2.6.3", 924 | "tar": "^4.4.6", 925 | "which": "^1.3.1", 926 | "zen-observable": "^0.8.14" 927 | } 928 | }, 929 | "purescript-psa": { 930 | "version": "0.7.3", 931 | "resolved": "https://registry.npmjs.org/purescript-psa/-/purescript-psa-0.7.3.tgz", 932 | "integrity": "sha512-qcnhruybTHVunhJqAuurOEWnz1BOOc/7mpcnyH5yxm5caYCejxq8GOE4ZNWbiPMeTlcG79qUPIOz7gx5OVmk2Q==", 933 | "dev": true 934 | }, 935 | "purty": { 936 | "version": "6.2.0", 937 | "resolved": "https://registry.npmjs.org/purty/-/purty-6.2.0.tgz", 938 | "integrity": "sha512-JfT8kJHSyxuOFQtRiH2x55SiPxXZsSdedQlZap8JehQ7KzB49B5C9cWwVybtSB36BdADQcxPvtw8D52z4EPnBw==", 939 | "dev": true 940 | }, 941 | "qs": { 942 | "version": "6.5.2", 943 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 944 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", 945 | "dev": true 946 | }, 947 | "readable-stream": { 948 | "version": "2.3.7", 949 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 950 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 951 | "dev": true, 952 | "requires": { 953 | "core-util-is": "~1.0.0", 954 | "inherits": "~2.0.3", 955 | "isarray": "~1.0.0", 956 | "process-nextick-args": "~2.0.0", 957 | "safe-buffer": "~5.1.1", 958 | "string_decoder": "~1.1.1", 959 | "util-deprecate": "~1.0.1" 960 | } 961 | }, 962 | "request": { 963 | "version": "2.88.2", 964 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", 965 | "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", 966 | "dev": true, 967 | "requires": { 968 | "aws-sign2": "~0.7.0", 969 | "aws4": "^1.8.0", 970 | "caseless": "~0.12.0", 971 | "combined-stream": "~1.0.6", 972 | "extend": "~3.0.2", 973 | "forever-agent": "~0.6.1", 974 | "form-data": "~2.3.2", 975 | "har-validator": "~5.1.3", 976 | "http-signature": "~1.2.0", 977 | "is-typedarray": "~1.0.0", 978 | "isstream": "~0.1.2", 979 | "json-stringify-safe": "~5.0.1", 980 | "mime-types": "~2.1.19", 981 | "oauth-sign": "~0.9.0", 982 | "performance-now": "^2.1.0", 983 | "qs": "~6.5.2", 984 | "safe-buffer": "^5.1.2", 985 | "tough-cookie": "~2.5.0", 986 | "tunnel-agent": "^0.6.0", 987 | "uuid": "^3.3.2" 988 | } 989 | }, 990 | "restore-cursor": { 991 | "version": "2.0.0", 992 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 993 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 994 | "dev": true, 995 | "requires": { 996 | "onetime": "^2.0.0", 997 | "signal-exit": "^3.0.2" 998 | }, 999 | "dependencies": { 1000 | "mimic-fn": { 1001 | "version": "1.2.0", 1002 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 1003 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", 1004 | "dev": true 1005 | }, 1006 | "onetime": { 1007 | "version": "2.0.1", 1008 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 1009 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 1010 | "dev": true, 1011 | "requires": { 1012 | "mimic-fn": "^1.0.0" 1013 | } 1014 | } 1015 | } 1016 | }, 1017 | "rimraf": { 1018 | "version": "2.7.1", 1019 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1020 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1021 | "dev": true, 1022 | "requires": { 1023 | "glob": "^7.1.3" 1024 | } 1025 | }, 1026 | "run-queue": { 1027 | "version": "1.0.3", 1028 | "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", 1029 | "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", 1030 | "dev": true, 1031 | "requires": { 1032 | "aproba": "^1.1.1" 1033 | } 1034 | }, 1035 | "safe-buffer": { 1036 | "version": "5.1.2", 1037 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1038 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1039 | "dev": true 1040 | }, 1041 | "safer-buffer": { 1042 | "version": "2.1.2", 1043 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1044 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1045 | "dev": true 1046 | }, 1047 | "shebang-command": { 1048 | "version": "2.0.0", 1049 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1050 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1051 | "dev": true, 1052 | "requires": { 1053 | "shebang-regex": "^3.0.0" 1054 | } 1055 | }, 1056 | "shebang-regex": { 1057 | "version": "3.0.0", 1058 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1059 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1060 | "dev": true 1061 | }, 1062 | "signal-exit": { 1063 | "version": "3.0.3", 1064 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 1065 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", 1066 | "dev": true 1067 | }, 1068 | "spago": { 1069 | "version": "0.16.0", 1070 | "resolved": "https://registry.npmjs.org/spago/-/spago-0.16.0.tgz", 1071 | "integrity": "sha512-I7CpLNM+3EPqLeqrhQHPa8U7J1C90XzMIzrzDtlZQ0TeloseulopTd5l2hzhjaj5DrcVtYhYkh3DVY1QDh8+ZA==", 1072 | "dev": true, 1073 | "requires": { 1074 | "request": "^2.88.0", 1075 | "tar": "^4.4.8" 1076 | } 1077 | }, 1078 | "sshpk": { 1079 | "version": "1.16.1", 1080 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 1081 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 1082 | "dev": true, 1083 | "requires": { 1084 | "asn1": "~0.2.3", 1085 | "assert-plus": "^1.0.0", 1086 | "bcrypt-pbkdf": "^1.0.0", 1087 | "dashdash": "^1.12.0", 1088 | "ecc-jsbn": "~0.1.1", 1089 | "getpass": "^0.1.1", 1090 | "jsbn": "~0.1.0", 1091 | "safer-buffer": "^2.0.2", 1092 | "tweetnacl": "~0.14.0" 1093 | } 1094 | }, 1095 | "ssri": { 1096 | "version": "6.0.1", 1097 | "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", 1098 | "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", 1099 | "dev": true, 1100 | "requires": { 1101 | "figgy-pudding": "^3.5.1" 1102 | } 1103 | }, 1104 | "stream-each": { 1105 | "version": "1.2.3", 1106 | "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", 1107 | "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", 1108 | "dev": true, 1109 | "requires": { 1110 | "end-of-stream": "^1.1.0", 1111 | "stream-shift": "^1.0.0" 1112 | } 1113 | }, 1114 | "stream-shift": { 1115 | "version": "1.0.1", 1116 | "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", 1117 | "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", 1118 | "dev": true 1119 | }, 1120 | "string-width": { 1121 | "version": "3.1.0", 1122 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1123 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1124 | "dev": true, 1125 | "requires": { 1126 | "emoji-regex": "^7.0.1", 1127 | "is-fullwidth-code-point": "^2.0.0", 1128 | "strip-ansi": "^5.1.0" 1129 | } 1130 | }, 1131 | "string_decoder": { 1132 | "version": "1.1.1", 1133 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1134 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1135 | "dev": true, 1136 | "requires": { 1137 | "safe-buffer": "~5.1.0" 1138 | } 1139 | }, 1140 | "strip-ansi": { 1141 | "version": "5.2.0", 1142 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1143 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1144 | "dev": true, 1145 | "requires": { 1146 | "ansi-regex": "^4.1.0" 1147 | } 1148 | }, 1149 | "strip-final-newline": { 1150 | "version": "2.0.0", 1151 | "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", 1152 | "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", 1153 | "dev": true 1154 | }, 1155 | "supports-color": { 1156 | "version": "5.5.0", 1157 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1158 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1159 | "dev": true, 1160 | "requires": { 1161 | "has-flag": "^3.0.0" 1162 | } 1163 | }, 1164 | "tar": { 1165 | "version": "4.4.13", 1166 | "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", 1167 | "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", 1168 | "dev": true, 1169 | "requires": { 1170 | "chownr": "^1.1.1", 1171 | "fs-minipass": "^1.2.5", 1172 | "minipass": "^2.8.6", 1173 | "minizlib": "^1.2.1", 1174 | "mkdirp": "^0.5.0", 1175 | "safe-buffer": "^5.1.2", 1176 | "yallist": "^3.0.3" 1177 | } 1178 | }, 1179 | "through2": { 1180 | "version": "2.0.5", 1181 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", 1182 | "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", 1183 | "dev": true, 1184 | "requires": { 1185 | "readable-stream": "~2.3.6", 1186 | "xtend": "~4.0.1" 1187 | } 1188 | }, 1189 | "tough-cookie": { 1190 | "version": "2.5.0", 1191 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", 1192 | "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", 1193 | "dev": true, 1194 | "requires": { 1195 | "psl": "^1.1.28", 1196 | "punycode": "^2.1.1" 1197 | } 1198 | }, 1199 | "tunnel-agent": { 1200 | "version": "0.6.0", 1201 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1202 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 1203 | "dev": true, 1204 | "requires": { 1205 | "safe-buffer": "^5.0.1" 1206 | } 1207 | }, 1208 | "tweetnacl": { 1209 | "version": "0.14.5", 1210 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 1211 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", 1212 | "dev": true 1213 | }, 1214 | "typedarray": { 1215 | "version": "0.0.6", 1216 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1217 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1218 | "dev": true 1219 | }, 1220 | "unique-filename": { 1221 | "version": "1.1.1", 1222 | "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", 1223 | "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", 1224 | "dev": true, 1225 | "requires": { 1226 | "unique-slug": "^2.0.0" 1227 | } 1228 | }, 1229 | "unique-slug": { 1230 | "version": "2.0.2", 1231 | "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", 1232 | "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", 1233 | "dev": true, 1234 | "requires": { 1235 | "imurmurhash": "^0.1.4" 1236 | } 1237 | }, 1238 | "uri-js": { 1239 | "version": "4.4.0", 1240 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", 1241 | "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", 1242 | "dev": true, 1243 | "requires": { 1244 | "punycode": "^2.1.0" 1245 | } 1246 | }, 1247 | "util-deprecate": { 1248 | "version": "1.0.2", 1249 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1250 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1251 | "dev": true 1252 | }, 1253 | "uuid": { 1254 | "version": "3.4.0", 1255 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", 1256 | "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", 1257 | "dev": true 1258 | }, 1259 | "verror": { 1260 | "version": "1.10.0", 1261 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 1262 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 1263 | "dev": true, 1264 | "requires": { 1265 | "assert-plus": "^1.0.0", 1266 | "core-util-is": "1.0.2", 1267 | "extsprintf": "^1.2.0" 1268 | } 1269 | }, 1270 | "which": { 1271 | "version": "1.3.1", 1272 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1273 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1274 | "dev": true, 1275 | "requires": { 1276 | "isexe": "^2.0.0" 1277 | } 1278 | }, 1279 | "wrap-ansi": { 1280 | "version": "5.1.0", 1281 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", 1282 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", 1283 | "dev": true, 1284 | "requires": { 1285 | "ansi-styles": "^3.2.0", 1286 | "string-width": "^3.0.0", 1287 | "strip-ansi": "^5.0.0" 1288 | } 1289 | }, 1290 | "wrappy": { 1291 | "version": "1.0.2", 1292 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1293 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1294 | "dev": true 1295 | }, 1296 | "xtend": { 1297 | "version": "4.0.2", 1298 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1299 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 1300 | "dev": true 1301 | }, 1302 | "y18n": { 1303 | "version": "4.0.0", 1304 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", 1305 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", 1306 | "dev": true 1307 | }, 1308 | "yallist": { 1309 | "version": "3.1.1", 1310 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 1311 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 1312 | "dev": true 1313 | }, 1314 | "zen-observable": { 1315 | "version": "0.8.15", 1316 | "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", 1317 | "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==", 1318 | "dev": true 1319 | } 1320 | } 1321 | } 1322 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-apiary", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "purescript": "^0.13.8", 12 | "purescript-psa": "^0.7.3", 13 | "purty": "^6.2.0", 14 | "spago": "^0.16.0" 15 | }, 16 | "scripts": { 17 | "build": "spago build", 18 | "docs": "spago docs --format markdown" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/robertdp/purescript-apiary.git" 23 | }, 24 | "author": "", 25 | "license": "ISC", 26 | "bugs": { 27 | "url": "https://github.com/robertdp/purescript-apiary/issues" 28 | }, 29 | "homepage": "https://github.com/robertdp/purescript-apiary#readme" 30 | } 31 | -------------------------------------------------------------------------------- /packages.dhall: -------------------------------------------------------------------------------- 1 | {- 2 | Welcome to your new Dhall package-set! 3 | 4 | Below are instructions for how to edit this file for most use 5 | cases, so that you don't need to know Dhall to use it. 6 | 7 | ## Warning: Don't Move This Top-Level Comment! 8 | 9 | Due to how `dhall format` currently works, this comment's 10 | instructions cannot appear near corresponding sections below 11 | because `dhall format` will delete the comment. However, 12 | it will not delete a top-level comment like this one. 13 | 14 | ## Use Cases 15 | 16 | Most will want to do one or both of these options: 17 | 1. Override/Patch a package's dependency 18 | 2. Add a package not already in the default package set 19 | 20 | This file will continue to work whether you use one or both options. 21 | Instructions for each option are explained below. 22 | 23 | ### Overriding/Patching a package 24 | 25 | Purpose: 26 | - Change a package's dependency to a newer/older release than the 27 | default package set's release 28 | - Use your own modified version of some dependency that may 29 | include new API, changed API, removed API by 30 | using your custom git repo of the library rather than 31 | the package set's repo 32 | 33 | Syntax: 34 | Replace the overrides' "{=}" (an empty record) with the following idea 35 | The "//" or "⫽" means "merge these two records and 36 | when they have the same value, use the one on the right:" 37 | ------------------------------- 38 | let override = 39 | { packageName = 40 | upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" } 41 | , packageName = 42 | upstream.packageName // { version = "v4.0.0" } 43 | , packageName = 44 | upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" } 45 | } 46 | ------------------------------- 47 | 48 | Example: 49 | ------------------------------- 50 | let overrides = 51 | { halogen = 52 | upstream.halogen // { version = "master" } 53 | , halogen-vdom = 54 | upstream.halogen-vdom // { version = "v4.0.0" } 55 | } 56 | ------------------------------- 57 | 58 | ### Additions 59 | 60 | Purpose: 61 | - Add packages that aren't already included in the default package set 62 | 63 | Syntax: 64 | Replace the additions' "{=}" (an empty record) with the following idea: 65 | ------------------------------- 66 | let additions = 67 | { package-name = 68 | { dependencies = 69 | [ "dependency1" 70 | , "dependency2" 71 | ] 72 | , repo = 73 | "https://example.com/path/to/git/repo.git" 74 | , version = 75 | "tag ('v4.0.0') or branch ('master')" 76 | } 77 | , package-name = 78 | { dependencies = 79 | [ "dependency1" 80 | , "dependency2" 81 | ] 82 | , repo = 83 | "https://example.com/path/to/git/repo.git" 84 | , version = 85 | "tag ('v4.0.0') or branch ('master')" 86 | } 87 | , etc. 88 | } 89 | ------------------------------- 90 | 91 | Example: 92 | ------------------------------- 93 | let additions = 94 | { benchotron = 95 | { dependencies = 96 | [ "arrays" 97 | , "exists" 98 | , "profunctor" 99 | , "strings" 100 | , "quickcheck" 101 | , "lcg" 102 | , "transformers" 103 | , "foldable-traversable" 104 | , "exceptions" 105 | , "node-fs" 106 | , "node-buffer" 107 | , "node-readline" 108 | , "datetime" 109 | , "now" 110 | ] 111 | , repo = 112 | "https://github.com/hdgarrood/purescript-benchotron.git" 113 | , version = 114 | "v7.0.0" 115 | } 116 | } 117 | ------------------------------- 118 | -} 119 | 120 | 121 | let upstream = 122 | https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20200922/packages.dhall sha256:5edc9af74593eab8834d7e324e5868a3d258bbab75c5531d2eb770d4324a2900 123 | 124 | let overrides = {=} 125 | 126 | let additions = {=} 127 | 128 | in upstream // overrides // additions 129 | -------------------------------------------------------------------------------- /spago.dhall: -------------------------------------------------------------------------------- 1 | {- 2 | Welcome to a Spago project! 3 | You can edit this file as you like. 4 | -} 5 | { name = "apiary" 6 | , dependencies = [ "affjax", "media-types", "simple-json" ] 7 | , packages = ./packages.dhall 8 | , sources = [ "src/**/*.purs", "test/**/*.purs" ] 9 | } 10 | -------------------------------------------------------------------------------- /src/Apiary.purs: -------------------------------------------------------------------------------- 1 | module Apiary 2 | ( module Affjax.RequestHeader 3 | , module Client 4 | , module Media 5 | , module Request 6 | , module Response 7 | , module Route 8 | , module Types 9 | , module Url 10 | ) where 11 | 12 | import Affjax.RequestHeader (RequestHeader(..)) as Affjax.RequestHeader 13 | import Apiary.Client (fetch, makeRequest) as Client 14 | import Apiary.Media (class DecodeMedia, class EncodeMedia, class MediaType, JSON, decodeMedia, encodeMedia, mediaType) as Media 15 | import Apiary.Request (class BuildRequest, class BuildUrl, class PrepareQueryParams, class ReplacePathParams, buildPath, buildQuery, buildRequest, buildUrl) as Request 16 | import Apiary.Response (class DecodeResponse, decodeResponse) as Response 17 | import Apiary.Route (DELETE, GET, PATCH, POST, PUT, Route(..)) as Route 18 | import Apiary.Types (Error(..), None, Request, Response, URL, emptyRequest, none) as Types 19 | import Apiary.Url (class DecodeParam, class EncodeParam, decodeParam, encodeParam) as Url 20 | -------------------------------------------------------------------------------- /src/Apiary/Client.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Client where 2 | 3 | import Prelude 4 | import Affjax (defaultRequest) 5 | import Affjax as Affjax 6 | import Affjax.RequestBody as RequestBody 7 | import Affjax.ResponseFormat as ResponseFormat 8 | import Apiary.Request (class BuildRequest, buildRequest) 9 | import Apiary.Response (class DecodeResponse, decodeResponse) 10 | import Apiary.Types (Error(..), Request, Response) 11 | import Control.Comonad (extract) 12 | import Control.Monad.Except (ExceptT(..), mapExceptT, runExceptT, withExcept, withExceptT) 13 | import Data.Either (Either(..)) 14 | import Data.Maybe (Maybe(..)) 15 | import Effect.Aff (Aff) 16 | import Type.Proxy (Proxy(..)) 17 | 18 | makeRequest :: 19 | forall route params query body rep response. 20 | BuildRequest route params query body rep => 21 | DecodeResponse rep response => 22 | route -> 23 | (Request -> Request) -> 24 | params -> 25 | query -> 26 | body -> 27 | Aff (Either Error response) 28 | makeRequest route transform params query body = runExceptT $ decode =<< fetch request 29 | where 30 | request :: Request 31 | request = transform $ buildRequest route params query body 32 | 33 | decode :: Response -> ExceptT Error Aff response 34 | decode text = 35 | mapExceptT (pure <<< extract) 36 | $ withExcept (_ $ request) 37 | $ decodeResponse (Proxy :: _ rep) text 38 | 39 | fetch :: Request -> ExceptT Error Aff Response 40 | fetch { method, url, headers, body } = do 41 | response <- withExceptT RuntimeError $ ExceptT runRequest 42 | pure 43 | { status: response.status 44 | , headers: response.headers 45 | , body: response.body 46 | } 47 | where 48 | runRequest = 49 | Affjax.request 50 | $ defaultRequest 51 | { method = Left method 52 | , url = url 53 | , headers = headers 54 | , responseFormat = ResponseFormat.string 55 | , content = 56 | case body of 57 | "" -> Nothing 58 | body' -> pure (RequestBody.String body') 59 | } 60 | -------------------------------------------------------------------------------- /src/Apiary/Media.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Media where 2 | 3 | import Prelude 4 | import Apiary.Types (None, none) 5 | import Data.Maybe (Maybe(..)) 6 | import Data.MediaType (MediaType) 7 | import Data.MediaType.Common (applicationJSON, textPlain) 8 | import Foreign (F) 9 | import Simple.JSON (class ReadForeign, class WriteForeign, readJSON', writeJSON) 10 | 11 | class MediaType rep where 12 | mediaType :: forall proxy. proxy rep -> Maybe MediaType 13 | 14 | class EncodeMedia rep a | rep -> a where 15 | encodeMedia :: forall proxy. proxy rep -> a -> String 16 | 17 | class DecodeMedia rep a | rep -> a where 18 | decodeMedia :: forall proxy. proxy rep -> String -> F a 19 | 20 | instance mediaTypeNone :: MediaType None where 21 | mediaType _ = Nothing 22 | 23 | instance encodeMediaNone :: EncodeMedia None None where 24 | encodeMedia _ _ = "" 25 | 26 | instance decodeMediaNone :: DecodeMedia None None where 27 | decodeMedia _ _ = pure none 28 | 29 | instance mediaTypeString :: MediaType String where 30 | mediaType _ = Just textPlain 31 | 32 | instance encodeMediaString :: EncodeMedia String String where 33 | encodeMedia _ a = a 34 | 35 | instance decodeMediaString :: DecodeMedia String String where 36 | decodeMedia _ a = pure a 37 | 38 | data JSON a 39 | = JSON 40 | 41 | instance mediaTypeJSON :: MediaType (JSON a) where 42 | mediaType _ = Just applicationJSON 43 | 44 | instance encodeMediaJSON :: (WriteForeign a) => EncodeMedia (JSON a) a where 45 | encodeMedia _ = writeJSON 46 | 47 | instance decodeMediaJSON :: (ReadForeign a) => DecodeMedia (JSON a) a where 48 | decodeMedia _ = readJSON' 49 | -------------------------------------------------------------------------------- /src/Apiary/Method.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Method 2 | ( module Data.HTTP.Method 3 | , class RequestMethod 4 | , toMethod 5 | ) where 6 | 7 | import Data.HTTP.Method (Method(..)) 8 | import Data.HTTP.Method (Method(..)) as Data.HTTP.Method 9 | import Data.Symbol (SProxy) 10 | import Partial.Unsafe (unsafeCrashWith) 11 | import Prim.TypeError (class Fail, Beside, Text) 12 | 13 | class RequestMethod (method :: Symbol) where 14 | toMethod :: SProxy method -> Method 15 | 16 | instance requestMethodGET :: RequestMethod "GET" where 17 | toMethod _ = GET 18 | else instance requestMethodPOST :: RequestMethod "POST" where 19 | toMethod _ = POST 20 | else instance requestMethodPUT :: RequestMethod "PUT" where 21 | toMethod _ = PUT 22 | else instance requestMethodHEAD :: RequestMethod "PATCH" where 23 | toMethod _ = PATCH 24 | else instance requestMethodDELETE :: RequestMethod "DELETE" where 25 | toMethod _ = DELETE 26 | else instance requestMethodFail :: 27 | Fail (Beside (Text "Unsupported request method: ") (Text method)) => 28 | RequestMethod method where 29 | toMethod _ = unsafeCrashWith "impossible" 30 | -------------------------------------------------------------------------------- /src/Apiary/Request.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Request 2 | ( class BuildRequest 3 | , class BuildUrl 4 | , class PrepareQueryParams 5 | , class ReplacePathParams 6 | , buildPath 7 | , buildQuery 8 | , buildRequest 9 | , buildUrl 10 | , prepareQueryParams 11 | , replacePathParams 12 | ) where 13 | 14 | import Prelude 15 | import Affjax.RequestHeader (RequestHeader(..)) 16 | import Apiary.Media (class EncodeMedia, class MediaType, encodeMedia, mediaType) 17 | import Apiary.Method (class RequestMethod, toMethod) 18 | import Apiary.Response (class DecodeResponse) 19 | import Apiary.Route (class PrepareSpec, Route) 20 | import Apiary.Types (None, Request) 21 | import Apiary.Url as Url 22 | import Control.Monad.ST (ST) 23 | import Data.Array (intercalate) 24 | import Data.Array as Array 25 | import Data.Array.ST as STArray 26 | import Data.Either (either) 27 | import Data.Foldable (traverse_) 28 | import Data.Maybe (Maybe, maybe) 29 | import Data.String as String 30 | import Data.String.Regex as Regex 31 | import Data.String.Regex.Flags as RegexFlags 32 | import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol) 33 | import Prim.Row (class Cons) 34 | import Prim.RowList (class RowToList, Cons, Nil, kind RowList) 35 | import Record as Record 36 | import Type.Data.RowList (RLProxy(..)) 37 | import Type.Proxy (Proxy(..)) 38 | 39 | class BuildRequest route params query body rep | route -> params query body rep where 40 | buildRequest :: route -> params -> query -> body -> Request 41 | 42 | instance buildRequestRouteGET :: 43 | ( PrepareSpec 44 | spec 45 | { path :: params 46 | , query :: query 47 | , body :: None 48 | , response :: response 49 | } 50 | , BuildUrl params query 51 | , DecodeResponse response response' 52 | , IsSymbol path 53 | ) => 54 | BuildRequest (Route "GET" path spec) params query None response where 55 | buildRequest _ = buildRequest_ (SProxy :: _ "GET") (SProxy :: _ path) (Proxy :: _ None) 56 | else instance buildRequestRouteRest :: 57 | ( PrepareSpec 58 | spec 59 | { path :: params 60 | , query :: query 61 | , body :: body 62 | , response :: response 63 | } 64 | , RequestMethod method 65 | , BuildUrl params query 66 | , MediaType body 67 | , EncodeMedia body body' 68 | , DecodeResponse response response' 69 | , IsSymbol path 70 | ) => 71 | BuildRequest (Route method path spec) params query body' response where 72 | buildRequest _ = buildRequest_ (SProxy :: _ method) (SProxy :: _ path) (Proxy :: _ body) 73 | 74 | buildRequest_ :: 75 | forall method path params query proxy bodyRep body. 76 | RequestMethod method => 77 | IsSymbol path => 78 | BuildUrl params query => 79 | MediaType bodyRep => 80 | EncodeMedia bodyRep body => 81 | SProxy method -> 82 | SProxy path -> 83 | proxy bodyRep -> 84 | params -> 85 | query -> 86 | body -> 87 | Request 88 | buildRequest_ method path bodyRep params query body = 89 | { method: toMethod method 90 | , url: buildUrl params query (reflectSymbol path) 91 | , headers: maybe [] (Array.singleton <<< ContentType) (mediaType bodyRep) 92 | , body: encodeMedia bodyRep body 93 | } 94 | 95 | class BuildUrl params query where 96 | buildUrl :: params -> query -> String -> String 97 | 98 | instance buildUrlPathAndQuery :: 99 | ( RowToList pathParams pathParamList 100 | , RowToList queryParams queryParamList 101 | , ReplacePathParams pathParams pathParamList 102 | , PrepareQueryParams queryParams queryParamList 103 | ) => 104 | BuildUrl { | pathParams } { | queryParams } where 105 | buildUrl pathParams queryParams url = path <> prefix query 106 | where 107 | path = buildPath pathParams url 108 | 109 | query = buildQuery queryParams 110 | 111 | prefix q = if String.null q then "" else "?" <> q 112 | else instance buildUrlPathOnly :: 113 | (BuildUrl path {}) => 114 | BuildUrl path None where 115 | buildUrl pathParams _ url = buildUrl pathParams {} url 116 | else instance buildUrlQueryOnly :: 117 | (BuildUrl {} query) => 118 | BuildUrl None query where 119 | buildUrl _ queryParams url = buildUrl {} queryParams url 120 | else instance buildUrlNone :: 121 | BuildUrl None None where 122 | buildUrl _ _ url = buildUrl {} {} url 123 | 124 | buildPath :: forall params paramList. RowToList params paramList => ReplacePathParams params paramList => { | params } -> String -> String 125 | buildPath = replacePathParams (RLProxy :: _ paramList) 126 | 127 | class ReplacePathParams (params :: # Type) (paramList :: RowList) | paramList -> params where 128 | replacePathParams :: forall proxy. proxy paramList -> Record params -> String -> String 129 | 130 | instance replacePathParamsNil :: ReplacePathParams params Nil where 131 | replacePathParams _ _ = identity 132 | 133 | instance replacePathParamsCons :: 134 | ( IsSymbol name 135 | , Url.EncodeParam value 136 | , Cons name value params' params 137 | , ReplacePathParams params paramTail 138 | ) => 139 | ReplacePathParams params (Cons name value paramTail) where 140 | replacePathParams _ params url = replacePathParams (RLProxy :: _ paramTail) params replaced 141 | where 142 | regex = Regex.regex ("\\:" <> reflectSymbol (SProxy :: _ name) <> "\\b") RegexFlags.global 143 | 144 | replaced = either (const url) (\pattern -> Regex.replace pattern replacement url) regex 145 | 146 | replacement = Url.encodeParam $ Record.get (SProxy :: _ name) params 147 | 148 | buildQuery :: forall query queryList. RowToList query queryList => PrepareQueryParams query queryList => { | query } -> String 149 | buildQuery query = 150 | prepareQueryParams (RLProxy :: _ queryList) query STArray.empty 151 | # intercalate "&" 152 | 153 | class PrepareQueryParams (query :: # Type) (queryList :: RowList) | queryList -> query where 154 | prepareQueryParams :: 155 | forall proxy. 156 | proxy queryList -> 157 | Record query -> 158 | (forall h. ST h (STArray.STArray h String)) -> 159 | Array String 160 | 161 | instance prepareQueryParamsNil :: PrepareQueryParams params Nil where 162 | prepareQueryParams _ _ builder = STArray.run builder 163 | 164 | instance prepareQueryParamsConsArray :: 165 | ( IsSymbol name 166 | , Url.EncodeParam value 167 | , Cons name (Maybe value) query' query 168 | , PrepareQueryParams query queryTail 169 | ) => 170 | PrepareQueryParams query (Cons name (Maybe value) queryTail) where 171 | prepareQueryParams _ query builder = do 172 | prepareQueryParams (RLProxy :: _ queryTail) query do 173 | array <- builder 174 | traverse_ (flip STArray.push array) value 175 | pure array 176 | where 177 | name = SProxy :: _ name 178 | 179 | value = 180 | Record.get name query 181 | # map \v -> Url.encodeParam (reflectSymbol name) <> "=" <> Url.encodeParam v 182 | else instance prepareQueryParamsCons :: 183 | ( IsSymbol name 184 | , Url.EncodeParam value 185 | , Cons name value query' query 186 | , PrepareQueryParams query queryTail 187 | ) => 188 | PrepareQueryParams query (Cons name value queryTail) where 189 | prepareQueryParams _ query builder = do 190 | prepareQueryParams (RLProxy :: _ queryTail) query do 191 | array <- builder 192 | _ <- STArray.push value array 193 | pure array 194 | where 195 | name = SProxy :: _ name 196 | 197 | value = Url.encodeParam (reflectSymbol name) <> "=" <> Url.encodeParam (Record.get name query) 198 | -------------------------------------------------------------------------------- /src/Apiary/Response.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Response where 2 | 3 | import Prelude 4 | import Apiary.Media (class DecodeMedia, decodeMedia) 5 | import Apiary.Status (class ResponseStatus, Status) 6 | import Apiary.Status as Status 7 | import Apiary.Types (Error(..), None, Response, Request, none) 8 | import Control.Alt ((<|>)) 9 | import Control.Monad.Error.Class (throwError) 10 | import Control.Monad.Except (Except, withExcept) 11 | import Data.Maybe (isJust) 12 | import Data.Symbol (class IsSymbol) 13 | import Data.Variant (SProxy(..), Variant, expand, inj, prj) 14 | import Partial.Unsafe (unsafeCrashWith) 15 | import Prim.Row (class Cons, class Union) 16 | import Prim.RowList (class RowToList, kind RowList, Cons, Nil) 17 | import Type.Data.RowList (RLProxy(..)) 18 | import Type.Proxy (Proxy(..)) 19 | 20 | class DecodeResponse rep response | rep -> response where 21 | decodeResponse :: forall proxy. proxy rep -> Response -> Except (Request -> Error) response 22 | 23 | instance decodeResponseNone :: DecodeResponse None None where 24 | decodeResponse _ _ = pure none 25 | 26 | instance decodeResponseString :: DecodeResponse String String where 27 | decodeResponse _ response = pure response.body 28 | 29 | instance decodeResponseRecord :: 30 | ( RowToList responses responseList 31 | , DecodeResponseVariant result responseList 32 | ) => 33 | DecodeResponse { | responses } (Variant result) where 34 | decodeResponse _ = decodeResponseVariant (RLProxy :: _ responseList) 35 | 36 | class DecodeResponseVariant (response :: # Type) (responseList :: RowList) | responseList -> response where 37 | decodeResponseVariant :: forall proxy. proxy responseList -> Response -> Except (Request -> Error) (Variant response) 38 | 39 | instance decodeResponseVariantNil :: DecodeResponseVariant () Nil where 40 | -- | This will never be reached if the data originates from PureScript. 41 | decodeResponseVariant _ = throwError <<< flip UnexpectedResponse 42 | 43 | instance decodeResponseVariantCons :: 44 | ( IsSymbol status 45 | , ResponseStatus status 46 | , Cons status decoded variant' variant 47 | , DecodeResponseVariant variant' responseList 48 | , Union variant' a variant 49 | , DecodeMedia rep decoded 50 | ) => 51 | DecodeResponseVariant variant (Cons status rep responseList) where 52 | decodeResponseVariant _ response = 53 | (inj status <$> decodeStatus) 54 | <|> (expand <$> decodeRest) 55 | where 56 | status = SProxy :: _ status 57 | 58 | statusCode = Status.toStatusCode (Status.toStatus status) 59 | 60 | decodeStatus 61 | | response.status == statusCode = withExcept (\errs req -> DecodeError req response errs) $ decodeMedia (Proxy :: _ rep) response.body 62 | | otherwise = throwError $ flip UnexpectedResponse response 63 | 64 | decodeRest = decodeResponseVariant (RLProxy :: _ responseList) response 65 | 66 | toStatus :: 67 | forall response responseList. 68 | RowToList response responseList => 69 | ResponseVariantToStatus response responseList => 70 | Variant response -> 71 | Status 72 | toStatus = responseVariantToStatus (RLProxy :: _ responseList) 73 | 74 | class ResponseVariantToStatus (response :: # Type) (responseList :: RowList) | responseList -> response where 75 | responseVariantToStatus :: forall proxy. proxy responseList -> Variant response -> Status 76 | 77 | instance responseVariantToStatusNil :: ResponseVariantToStatus response Nil where 78 | -- | This will never be reached if the data originates from PureScript. 79 | responseVariantToStatus _ _ = unsafeCrashWith "Unmatchable response variant" 80 | 81 | instance responseVariantToStatusCons :: 82 | ( IsSymbol status 83 | , ResponseStatus status 84 | , Cons status body response' response 85 | , ResponseVariantToStatus response responseList 86 | ) => 87 | ResponseVariantToStatus response (Cons status body responseList) where 88 | responseVariantToStatus _ response = 89 | if isJust (prj (SProxy :: _ status) response) then 90 | Status.toStatus (SProxy :: _ status) 91 | else 92 | responseVariantToStatus (RLProxy :: _ responseList) response 93 | -------------------------------------------------------------------------------- /src/Apiary/Route.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Route where 2 | 3 | import Apiary.Types (None) 4 | import Prim.Row (class Nub, class Union) 5 | 6 | data Route (method :: Symbol) (path :: Symbol) spec 7 | = Route 8 | 9 | type SpecDefaults 10 | = ( path :: None 11 | , query :: None 12 | , body :: None 13 | , response :: None 14 | ) 15 | 16 | class PrepareSpec spec prepared | spec -> prepared 17 | 18 | instance prepareSpec :: 19 | ( Union spec SpecDefaults specWithDefaults 20 | , Nub specWithDefaults prepared 21 | ) => 22 | PrepareSpec (Record spec) (Record prepared) 23 | 24 | type GET 25 | = Route "GET" 26 | 27 | type PATCH 28 | = Route "PATCH" 29 | 30 | type POST 31 | = Route "POST" 32 | 33 | type PUT 34 | = Route "PUT" 35 | 36 | type DELETE 37 | = Route "DELETE" 38 | -------------------------------------------------------------------------------- /src/Apiary/Status.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Status where 2 | 3 | import Prelude 4 | import Affjax.StatusCode (StatusCode(..)) 5 | import Data.Symbol (SProxy(..)) 6 | import Partial.Unsafe (unsafeCrashWith) 7 | import Prim.TypeError (class Fail, Beside, Text) 8 | 9 | newtype Status 10 | = Status { code :: Int, reason :: String } 11 | 12 | instance eqStatus :: Eq Status where 13 | eq a b = code a == code b 14 | 15 | instance showStatus :: Show Status where 16 | show (Status s) = "(status " <> show s.code <> " " <> show s.reason <> ")" 17 | 18 | code :: Status -> Int 19 | code (Status s) = s.code 20 | 21 | reason :: Status -> String 22 | reason (Status s) = s.reason 23 | 24 | toStatusCode :: Status -> StatusCode 25 | toStatusCode (Status s) = StatusCode s.code 26 | 27 | status :: Int -> String -> Status 28 | status c r = Status { code: c, reason: r } 29 | 30 | ok :: Status 31 | ok = status 200 "OK" 32 | 33 | _ok = SProxy :: SProxy "ok" 34 | 35 | created :: Status 36 | created = status 201 "Created" 37 | 38 | _created = SProxy :: SProxy "created" 39 | 40 | noContent :: Status 41 | noContent = status 204 "No Content" 42 | 43 | _noContent = SProxy :: SProxy "noContent" 44 | 45 | notModified :: Status 46 | notModified = status 304 "Not Modified" 47 | 48 | _notModified = SProxy :: SProxy "notModified" 49 | 50 | badRequest :: Status 51 | badRequest = status 400 "Bad Request" 52 | 53 | _badRequest = SProxy :: SProxy "badRequest" 54 | 55 | unauthorized :: Status 56 | unauthorized = status 401 "Unauthorized" 57 | 58 | _unauthorized = SProxy :: SProxy "unauthorized" 59 | 60 | forbidden :: Status 61 | forbidden = status 403 "Forbidden" 62 | 63 | _forbidden = SProxy :: SProxy "forbidden" 64 | 65 | notFound :: Status 66 | notFound = status 404 "Not Found" 67 | 68 | _notFound = SProxy :: SProxy "notFound" 69 | 70 | conflict :: Status 71 | conflict = status 409 "Conflict" 72 | 73 | _conflict = SProxy :: SProxy "conflict" 74 | 75 | unprocessableEntity :: Status 76 | unprocessableEntity = status 422 "Unprocessable Entity" 77 | 78 | _unprocessableEntity = SProxy :: SProxy "unprocessableEntity" 79 | 80 | maintenanceInProgress :: Status 81 | maintenanceInProgress = status 520 "Maintenance In Progress" 82 | 83 | _maintenanceInProgress = SProxy :: SProxy "maintenanceInProgress" 84 | 85 | class ResponseStatus (status :: Symbol) where 86 | toStatus :: forall proxy. proxy status -> Status 87 | 88 | instance responseStatusOK :: ResponseStatus "ok" where 89 | toStatus _ = ok 90 | else instance responseStatusCreated :: ResponseStatus "created" where 91 | toStatus _ = created 92 | else instance responseStatusNoContent :: ResponseStatus "noContent" where 93 | toStatus _ = noContent 94 | else instance responseStatusNotModified :: ResponseStatus "notModified" where 95 | toStatus _ = notModified 96 | else instance responseStatusBadRequest :: ResponseStatus "badRequest" where 97 | toStatus _ = badRequest 98 | else instance responseStatusUnauthorized :: ResponseStatus "unauthorized" where 99 | toStatus _ = unauthorized 100 | else instance responseStatusForbidden :: ResponseStatus "forbidden" where 101 | toStatus _ = forbidden 102 | else instance responseStatusNotFound :: ResponseStatus "notFound" where 103 | toStatus _ = notFound 104 | else instance responseStatusConflict :: ResponseStatus "conflict" where 105 | toStatus _ = conflict 106 | else instance responseStatusUnprocessableEntity :: ResponseStatus "unprocessableEntity" where 107 | toStatus _ = unprocessableEntity 108 | else instance responseStatusFail :: 109 | Fail (Beside (Text "Unsupported response status: ") (Text status)) => 110 | ResponseStatus status where 111 | toStatus _ = unsafeCrashWith "impossible" 112 | -------------------------------------------------------------------------------- /src/Apiary/Types.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Types where 2 | 3 | import Prelude 4 | import Affjax as Affjax 5 | import Affjax.RequestHeader (RequestHeader) 6 | import Affjax.ResponseHeader (ResponseHeader) 7 | import Affjax.StatusCode (StatusCode) 8 | import Data.HTTP.Method (Method(..)) 9 | import Foreign (MultipleErrors) 10 | import Unsafe.Coerce (unsafeCoerce) 11 | 12 | type URL 13 | = String 14 | 15 | type Request 16 | = { method :: Method 17 | , url :: URL 18 | , headers :: Array RequestHeader 19 | , body :: String 20 | } 21 | 22 | emptyRequest :: Request 23 | emptyRequest = 24 | { method: GET 25 | , url: "" 26 | , headers: [] 27 | , body: "" 28 | } 29 | 30 | type Response 31 | = { status :: StatusCode 32 | , headers :: Array ResponseHeader 33 | , body :: String 34 | } 35 | 36 | data Error 37 | = RuntimeError Affjax.Error 38 | | DecodeError Request Response MultipleErrors 39 | | UnexpectedResponse Request Response 40 | 41 | instance showError :: Show Error where 42 | show (RuntimeError err) = "(RuntimeError {- " <> Affjax.printError err <> " -} )" 43 | show (DecodeError req res err) = "(DecodeError " <> show req <> " " <> show res <> " " <> show err <> ")" 44 | show (UnexpectedResponse req res) = "(UnexpectedResponse " <> show req <> " " <> show res <> ")" 45 | 46 | instance semigroupError :: Semigroup Error where 47 | append err@(RuntimeError _) _ = err 48 | append _ err@(RuntimeError _) = err 49 | append err@(DecodeError _ _ _) _ = err 50 | append _ err@(DecodeError _ _ _) = err 51 | append err@(UnexpectedResponse _ _) _ = err 52 | 53 | foreign import data None :: Type 54 | 55 | none :: None 56 | none = unsafeCoerce unit 57 | 58 | instance showNone :: Show None where 59 | show _ = "none" 60 | 61 | instance semigroupNone :: Semigroup None where 62 | append _ _ = none 63 | 64 | instance monoidNone :: Monoid None where 65 | mempty = none 66 | -------------------------------------------------------------------------------- /src/Apiary/Url.purs: -------------------------------------------------------------------------------- 1 | module Apiary.Url where 2 | 3 | import Prelude 4 | import Foreign (F) 5 | import Global.Unsafe (unsafeDecodeURIComponent, unsafeEncodeURIComponent) 6 | import Simple.JSON (readJSON', writeJSON) 7 | 8 | class EncodeParam a where 9 | encodeParam :: a -> String 10 | 11 | class DecodeParam a where 12 | decodeParam :: String -> F a 13 | 14 | instance encodeParamString :: EncodeParam String where 15 | encodeParam = unsafeEncodeURIComponent 16 | 17 | instance decodeParamString :: DecodeParam String where 18 | decodeParam = pure <<< unsafeDecodeURIComponent 19 | 20 | instance encodeParamBoolean :: EncodeParam Boolean where 21 | encodeParam = encodeParam <<< writeJSON 22 | 23 | instance decodeParamBoolean :: DecodeParam Boolean where 24 | decodeParam = decodeParam >=> readJSON' 25 | 26 | instance encodeParamInt :: EncodeParam Int where 27 | encodeParam = encodeParam <<< writeJSON 28 | 29 | instance decodeParamInt :: DecodeParam Int where 30 | decodeParam = decodeParam >=> readJSON' 31 | 32 | instance encodeParamNumber :: EncodeParam Number where 33 | encodeParam = encodeParam <<< writeJSON 34 | 35 | instance decodeParamNumber :: DecodeParam Number where 36 | decodeParam = decodeParam >=> readJSON' 37 | --------------------------------------------------------------------------------