{-# OPTIONS_GHC -Wno-unused-top-binds #-}

module Iri.Parsing.ByteString
  ( uri,
    httpUri,
    regName,
    uriQuery,
  )
where

import qualified Data.Attoparsec.ByteString as B
import qualified Data.ByteString as ByteString
import Iri.Data
import qualified Iri.Parsing.Attoparsec.ByteString as A
import Iri.Prelude

parser :: B.Parser a -> ByteString -> Either Text a
parser :: forall a. Parser a -> ByteString -> Either Text a
parser Parser a
parser =
  (String -> Either Text a)
-> (a -> Either Text a) -> Either String a -> Either Text a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Text -> Either Text a
forall a b. a -> Either a b
Left (Text -> Either Text a)
-> (String -> Text) -> String -> Either Text a
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. String -> Text
forall a. IsString a => String -> a
fromString) a -> Either Text a
forall a b. b -> Either a b
Right
    (Either String a -> Either Text a)
-> (ByteString -> Either String a) -> ByteString -> Either Text a
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Parser a -> ByteString -> Either String a
forall a. Parser a -> ByteString -> Either String a
B.parseOnly (Parser a
parser Parser a -> Parser ByteString () -> Parser a
forall a b.
Parser ByteString a -> Parser ByteString b -> Parser ByteString a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
forall t. Chunk t => Parser t ()
B.endOfInput)

-- |
-- Parser of a well-formed URI conforming to the RFC3986 standard into IRI.
-- Performs URL- and Punycode-decoding.
uri :: ByteString -> Either Text Iri
uri :: ByteString -> Either Text Iri
uri =
  Parser Iri -> ByteString -> Either Text Iri
forall a. Parser a -> ByteString -> Either Text a
parser Parser Iri
A.uri

-- |
-- Same as 'uri', but optimized specifially for the case of HTTP URIs.
httpUri :: ByteString -> Either Text HttpIri
httpUri :: ByteString -> Either Text HttpIri
httpUri =
  Parser HttpIri -> ByteString -> Either Text HttpIri
forall a. Parser a -> ByteString -> Either Text a
parser Parser HttpIri
A.httpUri

-- |
-- Domain name parser.
regName :: ByteString -> Either Text RegName
regName :: ByteString -> Either Text RegName
regName =
  Parser RegName -> ByteString -> Either Text RegName
forall a. Parser a -> ByteString -> Either Text a
parser Parser RegName
A.regName

-- |
-- Assuming we have a valid URI as input, extract the query part from it.
uriQuery :: ByteString -> Either Text Query
uriQuery :: ByteString -> Either Text Query
uriQuery ByteString
x =
  case (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
ByteString.break (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
63) ByteString
x of
    (ByteString
_, ByteString
questionAndAfterQuestion) -> case ByteString -> Maybe (Word8, ByteString)
ByteString.uncons ByteString
questionAndAfterQuestion of
      Just (Word8
_, ByteString
afterQuestion) -> case (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
ByteString.break (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
35) ByteString
afterQuestion of
        (ByteString
beforeHash, ByteString
_) -> Query -> Either Text Query
forall a b. b -> Either a b
Right (ByteString -> Query
Query ByteString
beforeHash)
      Maybe (Word8, ByteString)
Nothing ->
        Text -> Either Text Query
forall a b. a -> Either a b
Left Text
"Does not start with a question mark"

-- |
-- Assuming we have a valid URI as input, extract the fragment part from it.
uriFragment :: ByteString -> Fragment
uriFragment :: ByteString -> Fragment
uriFragment = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
ByteString.break (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
35) (ByteString -> (ByteString, ByteString))
-> ((ByteString, ByteString) -> Fragment) -> ByteString -> Fragment
forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> (ByteString, ByteString) -> ByteString
forall a b. (a, b) -> b
snd ((ByteString, ByteString) -> ByteString)
-> (ByteString -> Fragment) -> (ByteString, ByteString) -> Fragment
forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Int -> ByteString -> ByteString
ByteString.drop Int
1 (ByteString -> ByteString)
-> (ByteString -> Fragment) -> ByteString -> Fragment
forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> ByteString -> Fragment
Fragment