{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
#if (__GLASGOW_HASKELL__ >= 802)
{-# LANGUAGE DerivingStrategies #-}
#endif
module Swish.QName
( QName
, LName
, emptyLName
, newLName
, getLName
, newQName
, qnameFromURI
, getNamespace
, getLocalName
, getQNameURI
, qnameFromFilePath
)
where
import Data.Char (isAscii)
import Data.Maybe (fromMaybe)
import Data.Interned (intern, unintern)
import Data.Interned.URI (InternedURI)
import Data.Ord (comparing)
import Data.String (IsString(..))
import Network.URI (URI(..), URIAuth(..), parseURIReference)
import System.Directory (canonicalizePath)
import System.FilePath (splitFileName)
import qualified Data.Text as T
newtype LName = LName T.Text
deriving
#if (__GLASGOW_HASKELL__ >= 802)
stock
#endif
(LName -> LName -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LName -> LName -> Bool
$c/= :: LName -> LName -> Bool
== :: LName -> LName -> Bool
$c== :: LName -> LName -> Bool
Eq, Eq LName
LName -> LName -> Bool
LName -> LName -> Ordering
LName -> LName -> LName
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: LName -> LName -> LName
$cmin :: LName -> LName -> LName
max :: LName -> LName -> LName
$cmax :: LName -> LName -> LName
>= :: LName -> LName -> Bool
$c>= :: LName -> LName -> Bool
> :: LName -> LName -> Bool
$c> :: LName -> LName -> Bool
<= :: LName -> LName -> Bool
$c<= :: LName -> LName -> Bool
< :: LName -> LName -> Bool
$c< :: LName -> LName -> Bool
compare :: LName -> LName -> Ordering
$ccompare :: LName -> LName -> Ordering
Ord)
instance Show LName where
show :: LName -> [Char]
show (LName Text
t) = forall a. Show a => a -> [Char]
show Text
t
instance IsString LName where
fromString :: [Char] -> LName
fromString [Char]
s =
forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => [Char] -> a
error ([Char]
"Invalid local name: " forall a. [a] -> [a] -> [a]
++ [Char]
s)) forall a b. (a -> b) -> a -> b
$
Text -> Maybe LName
newLName ([Char] -> Text
T.pack [Char]
s)
emptyLName :: LName
emptyLName :: LName
emptyLName = Text -> LName
LName Text
""
newLName :: T.Text -> Maybe LName
newLName :: Text -> Maybe LName
newLName Text
l = if (Char -> Bool) -> Text -> Bool
T.any (\Char
c -> Char
c forall a. Eq a => a -> a -> Bool
== Char
' ' Bool -> Bool -> Bool
|| Bool -> Bool
not (Char -> Bool
isAscii Char
c)) Text
l then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just (Text -> LName
LName Text
l)
getLName :: LName -> T.Text
getLName :: LName -> Text
getLName (LName Text
l) = Text
l
data QName = QName !InternedURI URI LName
instance IsString QName where
fromString :: [Char] -> QName
fromString [Char]
s =
forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => [Char] -> a
error ([Char]
"QName conversion given an invalid URI: " forall a. [a] -> [a] -> [a]
++ [Char]
s))
([Char] -> Maybe URI
parseURIReference [Char]
s forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= URI -> Maybe QName
qnameFromURI)
instance Eq QName where
QName
u1 == :: QName -> QName -> Bool
== QName
u2 = QName -> URI
getQNameURI QName
u1 forall a. Eq a => a -> a -> Bool
== QName -> URI
getQNameURI QName
u2
instance Ord QName where
compare :: QName -> QName -> Ordering
compare = forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing QName -> URI
getQNameURI
instance Show QName where
show :: QName -> [Char]
show (QName InternedURI
u URI
_ LName
_) = [Char]
"<" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show InternedURI
u forall a. [a] -> [a] -> [a]
++ [Char]
">"
newQName ::
URI
-> LName
-> QName
newQName :: URI -> LName -> QName
newQName URI
ns l :: LName
l@(LName Text
local) =
let lstr :: [Char]
lstr = Text -> [Char]
T.unpack Text
local
uristr :: [Char]
uristr = forall a. Show a => a -> [Char]
show URI
ns forall a. [a] -> [a] -> [a]
++ [Char]
lstr
in case [Char] -> Maybe URI
parseURIReference [Char]
uristr of
Just URI
uri -> InternedURI -> URI -> LName -> QName
QName (forall t. Interned t => Uninterned t -> t
intern URI
uri) URI
ns LName
l
Maybe URI
_ -> forall a. HasCallStack => [Char] -> a
error forall a b. (a -> b) -> a -> b
$ [Char]
"Unable to combine " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show URI
ns forall a. [a] -> [a] -> [a]
++ [Char]
" with " forall a. [a] -> [a] -> [a]
++ [Char]
lstr
qnameFromURI ::
URI
-> Maybe QName
qnameFromURI :: URI -> Maybe QName
qnameFromURI URI
uri =
let uf :: [Char]
uf = URI -> [Char]
uriFragment URI
uri
up :: [Char]
up = URI -> [Char]
uriPath URI
uri
q0 :: Maybe QName
q0 = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ URI -> LName -> QName
start URI
uri LName
emptyLName
start :: URI -> LName -> QName
start = InternedURI -> URI -> LName -> QName
QName (forall t. Interned t => Uninterned t -> t
intern URI
uri)
in case [Char]
uf of
[Char]
"#" -> Maybe QName
q0
Char
'#':[Char]
xs -> URI -> LName -> QName
start (URI
uri {uriFragment :: [Char]
uriFragment = [Char]
"#"}) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Text -> Maybe LName
newLName ([Char] -> Text
T.pack [Char]
xs)
[Char]
"" -> case forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
== Char
'/') (forall a. [a] -> [a]
reverse [Char]
up) of
([Char]
"",[Char]
_) -> Maybe QName
q0
([Char]
_,[Char]
"") -> Maybe QName
q0
([Char]
rlname,[Char]
rpath) ->
URI -> LName -> QName
start (URI
uri {uriPath :: [Char]
uriPath = forall a. [a] -> [a]
reverse [Char]
rpath}) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap`
Text -> Maybe LName
newLName ([Char] -> Text
T.pack (forall a. [a] -> [a]
reverse [Char]
rlname))
[Char]
_ -> forall a. Maybe a
Nothing
getNamespace :: QName -> URI
getNamespace :: QName -> URI
getNamespace (QName InternedURI
_ URI
ns LName
_) = URI
ns
getLocalName :: QName -> LName
getLocalName :: QName -> LName
getLocalName (QName InternedURI
_ URI
_ LName
l) = LName
l
getQNameURI :: QName -> URI
getQNameURI :: QName -> URI
getQNameURI (QName InternedURI
u URI
_ LName
_) = forall t. Uninternable t => t -> Uninterned t
unintern InternedURI
u
qnameFromFilePath :: FilePath -> IO QName
qnameFromFilePath :: [Char] -> IO QName
qnameFromFilePath [Char]
fname = do
[Char]
ipath <- [Char] -> IO [Char]
canonicalizePath [Char]
fname
let ([Char]
dname, [Char]
lname) = [Char] -> ([Char], [Char])
splitFileName [Char]
ipath
nsuri :: URI
nsuri = [Char] -> Maybe URIAuth -> [Char] -> [Char] -> [Char] -> URI
URI [Char]
"file:" Maybe URIAuth
emptyAuth [Char]
dname [Char]
"" [Char]
""
uri :: URI
uri = [Char] -> Maybe URIAuth -> [Char] -> [Char] -> [Char] -> URI
URI [Char]
"file:" Maybe URIAuth
emptyAuth [Char]
ipath [Char]
"" [Char]
""
case [Char]
lname of
[Char]
"" -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ InternedURI -> URI -> LName -> QName
QName (forall t. Interned t => Uninterned t -> t
intern URI
nsuri) URI
nsuri LName
emptyLName
[Char]
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ InternedURI -> URI -> LName -> QName
QName (forall t. Interned t => Uninterned t -> t
intern URI
uri) URI
nsuri (Text -> LName
LName ([Char] -> Text
T.pack [Char]
lname))
emptyAuth :: Maybe URIAuth
emptyAuth :: Maybe URIAuth
emptyAuth = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> [Char] -> URIAuth
URIAuth [Char]
"" [Char]
"" [Char]
""