Skip to content

Updates for PS 0.15 #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .tidyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"importSort": "ide",
"importWrap": "auto",
"indent": 2,
"operatorsFile": null,
"ribbon": 1,
"typeArrowPlacement": "first",
"unicode": "never",
"width": 80
}
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Changelog

Notable changes are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

Breaking changes:
- Updates for PS v0.15
- Removed `joinQuery`: Use `append` instead.
- Removed `makeQuery'`: Use `URI.Query.fromString` instead.

New features:

Bugfixes:

Other improvements:

## [0.7.0] - TBD

Breaking changes:

New features:

Bugfixes:

Other improvements:
38 changes: 18 additions & 20 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,25 @@
"output"
],
"devDependencies": {
"purescript-psci-support": "^3.0.0",
"purescript-console": "^3.0.0"
"purescript-psci-support": "^6.0.0",
"purescript-console": "^6.0.0"
},
"dependencies": {
"purescript-prelude": "^3.1.0",
"purescript-maps": "^3.5.2",
"purescript-maybe": "^3.0.0",
"purescript-strings": "^3.3.1",
"purescript-lists": "^4.9.0",
"purescript-foreign": "^4.0.1",
"purescript-datetime": "^3.3.0",
"purescript-uri": "^4.0.0",
"purescript-pathy": "^4.0.0",
"purescript-transformers": "^3.4.0",
"purescript-string-parsers": "^3.0.1",
"purescript-js-date": "^5.1.0",
"purescript-control": "^3.3.0",
"purescript-monoid": "^3.1.0",
"purescript-tuples": "^4.1.0",
"purescript-exceptions": "^3.1.0",
"purescript-either": "^3.1.0",
"purescript-foreign-generic": "^5.0.0"
"purescript-prelude": "^6.0.0",
"purescript-ordered-collections": "^3.0.0",
"purescript-maybe": "^6.0.0",
"purescript-strings": "^6.0.0",
"purescript-lists": "^7.0.0",
"purescript-foreign": "^7.0.0",
"purescript-datetime": "^6.0.0",
"purescript-uri": "^9.0.0",
"purescript-pathy": "^9.0.0",
"purescript-transformers": "^6.0.0",
"purescript-string-parsers": "^8.0.0",
"purescript-js-date": "^8.0.0",
"purescript-control": "^6.0.0",
"purescript-tuples": "^7.0.0",
"purescript-exceptions": "^6.0.0",
"purescript-either": "^6.0.0"
}
}
6 changes: 2 additions & 4 deletions src/Network/HTTP/Types/Cookie.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,6 @@ function parse(str, options) {
}

// XXX Eventually give this a pure PureScript implementation.
function parseImpl(cookieString) {
export function parseImpl(cookieString) {
return parse(cookieString);
}

exports.parseImpl = parseImpl;
}
224 changes: 120 additions & 104 deletions src/Network/HTTP/Types/Cookie.purs
Original file line number Diff line number Diff line change
@@ -1,98 +1,104 @@
module Network.HTTP.Types.Cookie
( Cookie(Cookie)
, setName
, setValue
, setDomain
, setExpires
, setHttpOnly
, setMaxAge
, setPath
, setSecure
, parse
, stringify
, stringify'
) where

( Cookie(Cookie)
, setName
, setValue
, setDomain
, setExpires
, setHttpOnly
, setMaxAge
, setPath
, setSecure
, parse
, stringify
, stringify'
) where

import Control.Alt ((<|>))
import Control.Monad.Except (runExcept)
import Data.DateTime (DateTime)
import Data.DateTime.Instant (Instant, instant)
import Data.Either (Either(Left, Right), either)
import Data.JSDate (toDateTime)
import Data.List (List, intercalate)
import Data.Maybe (Maybe(Just, Nothing), fromMaybe)
import Data.String.NonEmpty as NES
import Data.Time.Duration (Milliseconds(Milliseconds))
import Foreign (Foreign, readNullOrUndefined, readUndefined, unsafeFromForeign)
import Parsing (runParser)
import Pathy (AbsDir, AbsFile, parseAbsDir, parseAbsFile, posixParser, rootDir)
import Prelude
( ($)
, (<>)
, (<$>)
, (<<<)
, (>>>)
, (>>=)
, class Show
, id
, map
, const
, show
)

import Control.Alt ((<|>))
import Control.Monad.Except (runExcept)
import Data.DateTime (DateTime)
import Data.Time.Duration (Milliseconds(Milliseconds))
import Data.DateTime.Instant (Instant, instant)
import Data.JSDate (toDateTime)
import Data.Either (Either(Left, Right), either)
import Data.Foreign
( Foreign
, readNullOrUndefined
, readUndefined
, unsafeFromForeign
)
import Data.List (List, intercalate)
import Data.Maybe (Maybe(Just, Nothing), fromMaybe)
import Data.Path.Pathy
( Abs
, Unsandboxed
, parseAbsDir
, parseAbsFile
, rootDir
)
import Data.URI (Host(NameAddress), URIPath)
import Data.URI.Host (parser)
import Text.Parsing.StringParser (runParser)
( class Show
, const
, identity
, map
, show
, ($)
, (<$>)
, (<<<)
, (<>)
, (>>=)
, (>>>)
)
import URI (Host(NameAddress))
import URI.Host (parser)
import URI.Host.RegName as RegName

-- | The cookie object we get back from 'parseImpl'.
newtype JSCookie = JSCookie
{ key :: String
, value :: String
-- You would expect the following fields to have the types that are
-- commented on them, however those are what the PureScript
-- representation of the type would be. Since JS has no types, we
-- represent them as whatever JS gives back, which is `Undefined|a`,
-- a.k.a., `Foreign`.
, domain :: Foreign -- ^ Undefined String
, expires :: Foreign -- ^ Undefined JSDate
, httpOnly :: Foreign -- ^ Undefined Boolean
, maxAge :: Foreign -- ^ Undefined Number
, path :: Foreign -- ^ Undefined String
, secure :: Foreign -- ^ Undefined Boolean
}
{ key :: String
, value :: String
-- You would expect the following fields to have the types that are
-- commented on them, however those are what the PureScript
-- representation of the type would be. Since JS has no types, we
-- represent them as whatever JS gives back, which is `Undefined|a`,
-- a.k.a., `Foreign`.
, domain :: Foreign -- ^ Undefined String
, expires :: Foreign -- ^ Undefined JSDate
, httpOnly :: Foreign -- ^ Undefined Boolean
, maxAge :: Foreign -- ^ Undefined Number
, path :: Foreign -- ^ Undefined String
, secure :: Foreign -- ^ Undefined Boolean
}

-- | An type that represents an HTTP Cookie.
newtype Cookie = Cookie
{ name :: String
, value :: String
, domain :: Maybe Host
, expires :: Maybe DateTime
, httpOnly :: Maybe Boolean
, maxAge :: Maybe Instant
, path :: URIPath Abs Unsandboxed
, secure :: Maybe Boolean
}
{ name :: String
, value :: String
, domain :: Maybe Host
, expires :: Maybe DateTime
, httpOnly :: Maybe Boolean
, maxAge :: Maybe Instant
, path :: Either AbsDir AbsFile
, secure :: Maybe Boolean
}

instance showCookie :: Show Cookie where
show (Cookie c) = "(Cookie {"
<> " name:" <> show c.name <> ","
<> " value:" <> show c.value <> ","
<> " domain: (" <> show c.domain <> "),"
<> " expires: (" <> show c.expires <> "),"
<> " httpOnly: (" <> show c.httpOnly <> "),"
<> " maxAge: (" <> show c.maxAge <> "),"
<> " path: (" <> show c.path <> "),"
<> " secure: (" <> show c.secure <> "),"
<> " })"
show (Cookie c) = "(Cookie {"
<> " name:"
<> show c.name
<> ","
<> " value:"
<> show c.value
<> ","
<> " domain: ("
<> show c.domain
<> "),"
<> " expires: ("
<> show c.expires
<> "),"
<> " httpOnly: ("
<> show c.httpOnly
<> "),"
<> " maxAge: ("
<> show c.maxAge
<> "),"
<> " path: ("
<> show c.path
<> "),"
<> " secure: ("
<> show c.secure
<> "),"
<> " })"

setName :: String -> Cookie -> Cookie
setName name (Cookie c) = Cookie c { name = name }
Expand All @@ -112,7 +118,7 @@ setHttpOnly httpOnly (Cookie c) = Cookie c { httpOnly = Just httpOnly }
setMaxAge :: Instant -> Cookie -> Cookie
setMaxAge maxAge (Cookie c) = Cookie c { maxAge = Just maxAge }

setPath :: URIPath Abs Unsandboxed -> Cookie -> Cookie
setPath :: Either AbsDir AbsFile -> Cookie -> Cookie
setPath path (Cookie c) = Cookie c { path = path }

setSecure :: Boolean -> Cookie -> Cookie
Expand All @@ -121,23 +127,33 @@ setSecure secure (Cookie c) = Cookie c { secure = Just secure }
-- | Converts a 'JSCookie' to a PureScript 'Cookie'.
toCookie :: JSCookie -> Cookie
toCookie (JSCookie c) = Cookie
{ name : c.key
, value : c.value
-- XXX If a host can't be parsed, just convert the string domain value into a NameAddress and return it;
-- but maybe we should throw here?
, domain : (\d -> either (const $ NameAddress d) id $ runParser parser d) <$> fromUndefined c.domain
, expires : fromUndefined c.expires >>= toDateTime
, httpOnly: fromUndefined c.httpOnly
, maxAge : fromUndefined c.maxAge >>= (Milliseconds >>> instant)
, path : fromMaybe (Left rootDir) $ fromNullOrUndefined c.path >>= \p -> (Left <$> parseAbsDir p) <|> (Right <$> parseAbsFile p)
, secure : fromUndefined c.secure
}
where
-- This `unsafeFromForeign` here means we're always trusting tough-cookie to parse values properly;
-- I think that's a pretty safe assumption.
fromUndefined :: forall a. Foreign -> Maybe a
fromUndefined = either (const Nothing) (unsafeFromForeign <$> _) <<< runExcept <<< readUndefined
fromNullOrUndefined = either (const Nothing) (unsafeFromForeign <$> _) <<< runExcept <<< readNullOrUndefined
{ name: c.key
, value: c.value
-- XXX If a host can't be parsed, just convert the string domain value into a NameAddress and return it;
-- but maybe we should throw here?
, domain:
( \d -> either (const $ NameAddress $ RegName.fromString d) identity $
runParser (NES.toString d) parser
)
<$>
(fromUndefined c.domain >>= NES.fromString)
, expires: fromUndefined c.expires >>= toDateTime
, httpOnly: fromUndefined c.httpOnly
, maxAge: fromUndefined c.maxAge >>= (Milliseconds >>> instant)
, path: fromMaybe (Left rootDir) $ fromNullOrUndefined c.path >>= \p ->
(Left <$> parseAbsDir posixParser p) <|>
(Right <$> parseAbsFile posixParser p)
, secure: fromUndefined c.secure
}
where
-- This `unsafeFromForeign` here means we're always trusting tough-cookie to parse values properly;
-- I think that's a pretty safe assumption.
fromUndefined :: forall a. Foreign -> Maybe a
fromUndefined = either (const Nothing) (unsafeFromForeign <$> _) <<< runExcept
<<< readUndefined
fromNullOrUndefined = either (const Nothing) (unsafeFromForeign <$> _)
<<< runExcept
<<< readNullOrUndefined

foreign import parseImpl :: String -> JSCookie

Expand All @@ -155,4 +171,4 @@ stringify (Cookie { name, value }) = name <> "=" <> value
-- | myCookieList` as special processing is needed to convert a 'List' of
-- | 'Cookie's into a RFC-compliant Cookie header value string.
stringify' :: List Cookie -> String
stringify' = map stringify >>> intercalate ";"
stringify' = map stringify >>> intercalate ";"
Loading