feat: resolveString, pathOrURLFromString

This commit is contained in:
orion 2023-12-28 17:56:07 -06:00
parent 6faac5b5c5
commit 4f94c15ae2
Signed by: orion
GPG Key ID: 6D4165AE4C928719
4 changed files with 65 additions and 5 deletions

View File

@ -18,6 +18,7 @@ workspace:
- prelude - prelude
- simple-json - simple-json
- strings - strings
- stringutils
- transformers - transformers
- tuples - tuples
test_dependencies: test_dependencies:
@ -83,6 +84,7 @@ workspace:
- spec - spec
- st - st
- strings - strings
- stringutils
- tailrec - tailrec
- transformers - transformers
- tuples - tuples
@ -6301,6 +6303,17 @@ packages:
- tuples - tuples
- unfoldable - unfoldable
- unsafe-coerce - unsafe-coerce
stringutils:
type: git
url: https://github.com/menelaos/purescript-stringutils.git
rev: 51d92cacd8c8102fc4e6137b4f709a2b11ca5186
dependencies:
- arrays
- integers
- maybe
- partial
- prelude
- strings
tailrec: tailrec:
type: git type: git
url: https://github.com/purescript/purescript-tailrec.git url: https://github.com/purescript/purescript-tailrec.git

View File

@ -31,6 +31,7 @@ package:
- prelude - prelude
- simple-json - simple-json
- strings - strings
- stringutils
- transformers - transformers
- tuples - tuples
workspace: workspace:

View File

@ -18,12 +18,14 @@ module Data.URL
, parts , parts
, password , password
, path , path
, pathOrURLFromString
, port , port
, query , query
, setQuery , setQuery
, protocol , protocol
, queryParamTuple , queryParamTuple
, resolve , resolve
, resolveString
, setHost , setHost
, setPassword , setPassword
, setPort , setPort
@ -38,7 +40,7 @@ import Prelude
import Control.Monad.Error.Class (liftEither, liftMaybe) import Control.Monad.Error.Class (liftEither, liftMaybe)
import Data.Array as Array import Data.Array as Array
import Data.Bifunctor (lmap) import Data.Bifunctor (lmap)
import Data.Either (Either) import Data.Either (Either(..), note)
import Data.Filterable (filter) import Data.Filterable (filter)
import Data.Foldable (class Foldable, foldl, intercalate) import Data.Foldable (class Foldable, foldl, intercalate)
import Data.FoldableWithIndex (foldlWithIndex) import Data.FoldableWithIndex (foldlWithIndex)
@ -51,7 +53,8 @@ import Data.Newtype (wrap)
import Data.Nullable (Nullable) import Data.Nullable (Nullable)
import Data.Nullable as Nullable import Data.Nullable as Nullable
import Data.Show.Generic (genericShow) import Data.Show.Generic (genericShow)
import Data.String as String import Data.String (null, replace, split) as String
import Data.String.Utils (startsWith) as String
import Data.Tuple.Nested (type (/\), (/\)) import Data.Tuple.Nested (type (/\), (/\))
import Foreign (ForeignError(..)) import Foreign (ForeignError(..))
import Partial.Unsafe (unsafePartial) import Partial.Unsafe (unsafePartial)
@ -134,6 +137,9 @@ foreign import setUsernameImpl :: String -> URL -> URL
fromString :: String -> Maybe URL fromString :: String -> Maybe URL
fromString = Nullable.toMaybe <<< fromStringImpl fromString = Nullable.toMaybe <<< fromStringImpl
pathOrURLFromString :: String -> Either Path URL
pathOrURLFromString s = note (pathFromString s) $ fromString s
parse :: String -> Either String URL parse :: String -> Either String URL
parse url = liftMaybe ("invalid URL: " <> url) $ Nullable.toMaybe $ fromStringImpl url parse url = liftMaybe ("invalid URL: " <> url) $ Nullable.toMaybe $ fromStringImpl url
@ -192,9 +198,11 @@ setQuery qs u =
pathFromString :: String -> Path pathFromString :: String -> Path
pathFromString s = pathFromString s =
let let
segments = filter (not <<< String.null) <<< String.split (wrap "/") segments =
filter (not <<< String.null)
<<< String.split (wrap "/")
in in
maybe PathEmpty PathAbsolute maybe PathEmpty (if String.startsWith "/" s then PathAbsolute else PathRelative)
$ filter (not <<< Array.null) $ filter (not <<< Array.null)
$ Just $ Just
$ segments s $ segments s
@ -231,6 +239,12 @@ addQuery u p =
infixl 3 addQuery as ? infixl 3 addQuery as ?
infixl 3 addQuery as & infixl 3 addQuery as &
resolveString :: String -> URL -> URL
resolveString s a =
case pathOrURLFromString s of
Right b -> b
Left p -> resolve p a
resolve :: Path -> URL -> URL resolve :: Path -> URL -> URL
resolve p u = resolve p u =
case p /\ path u of case p /\ path u of

View File

@ -3,11 +3,12 @@ module Test.Main where
import Prelude hiding ((/), (#)) import Prelude hiding ((/), (#))
import Control.Monad.Error.Class (liftMaybe, throwError) import Control.Monad.Error.Class (liftMaybe, throwError)
import Data.Either (Either(..), isRight)
import Data.Map as Map import Data.Map as Map
import Data.Maybe (Maybe(..), maybe) import Data.Maybe (Maybe(..), maybe)
import Data.Traversable (for_) import Data.Traversable (for_)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import Data.URL (URL, (#), (&), (/), (?)) import Data.URL (Path(..), URL, pathOrURLFromString, resolveString, toString, (#), (&), (/), (?))
import Data.URL as URL import Data.URL as URL
import Effect (Effect) import Effect (Effect)
import Effect.Aff (Aff, launchAff_) import Effect.Aff (Aff, launchAff_)
@ -37,6 +38,37 @@ main = launchAff_ $ runSpec [ consoleReporter ] do
case_ "localhost" case_ "localhost"
case_ "http://?feai#dfkvsj" case_ "http://?feai#dfkvsj"
describe "pathOrURLFromString" do
it "returns Right on valid URL" do
isRight (pathOrURLFromString "https://google.com") `shouldEqual` true
isRight (pathOrURLFromString "http://localhost?foo=bar&foo&foo&bar=baz") `shouldEqual` true
isRight (pathOrURLFromString "postgresql://user:pass@1.2.3.4:5432/dbname") `shouldEqual` true
it "returns Left on anything else" do
(pathOrURLFromString "/foo") `shouldEqual` (Left $ PathAbsolute [ "foo" ])
(pathOrURLFromString "./../../foo") `shouldEqual` (Left $ PathRelative [ ".", "..", "..", "foo" ])
(pathOrURLFromString "foo") `shouldEqual` (Left $ PathRelative [ "foo" ])
(pathOrURLFromString "") `shouldEqual` (Left PathEmpty)
(pathOrURLFromString "941389dfajifdjiao34910fd#$@?!") `shouldEqual` (Left $ PathRelative [ "941389dfajifdjiao34910fd#$@?!" ])
describe "resolveString" do
it "works" do
(shouldEqual "https://google.com/foo")
=<< toString
<$> resolveString "/foo"
<$> fromString_ "https://google.com/a/b/c/d/e"
(shouldEqual "https://google.com/foo/bar/baz/a")
=<< toString
<$> resolveString "./a"
<$> fromString_ "https://google.com/foo/bar/baz"
(shouldEqual "https://google.com/foo/a")
=<< toString
<$> resolveString "../../a"
<$> fromString_ "https://google.com/foo/bar/baz"
(shouldEqual "https://cheese.com/foo/bar")
=<< toString
<$> resolveString "https://cheese.com/foo/bar"
<$> fromString_ "https://google.com/foo/bar/baz"
describe "toString" do describe "toString" do
it "stringifies" do it "stringifies" do
let let