{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} module Dhall.Syntax.Import ( Directory(..) , File(..) , FilePrefix(..) , Import(..) , ImportHashed(..) , ImportMode(..) , ImportType(..) , URL(..) , Scheme(..) ) where import Data.Data (Data) import Data.Text (Text) import Dhall.Src (Src (..)) import Dhall.Syntax.Expr (Expr (..)) import Dhall.Syntax.Instances.Data () import Dhall.Syntax.Instances.Functor () import GHC.Generics (Generic) import qualified Dhall.Crypto {-| Internal representation of a directory that stores the path components in reverse order In other words, the directory @\/foo\/bar\/baz@ is encoded as @Directory { components = [ "baz", "bar", "foo" ] }@ -} newtype Directory = Directory { components :: [Text] } deriving (Data, Generic) {-| A `File` is a `directory` followed by one additional path component representing the `file` name -} data File = File { directory :: Directory , file :: Text } deriving (Data, Generic) -- | The beginning of a file path which anchors subsequent path components data FilePrefix = Absolute -- ^ Absolute path | Here -- ^ Path relative to @.@ | Parent -- ^ Path relative to @..@ | Home -- ^ Path relative to @~@ deriving (Data, Generic) -- | The URI scheme data Scheme = HTTP | HTTPS deriving (Data, Generic) -- | This type stores all of the components of a remote import data URL = URL { scheme :: Scheme , authority :: Text , path :: File , query :: Maybe Text , headers :: Maybe (Expr Src Import) } deriving (Data, Generic) -- | The type of import (i.e. local vs. remote vs. environment) data ImportType = Local FilePrefix File -- ^ Local path | Remote URL -- ^ URL of remote resource and optional headers stored in an import | Env Text -- ^ Environment variable | Missing deriving (Data, Generic) -- | How to interpret the import's contents (i.e. as Dhall code or raw text) data ImportMode = Code | RawText | Location | RawBytes deriving (Data, Generic) -- | A `ImportType` extended with an optional hash for semantic integrity checks data ImportHashed = ImportHashed { hash :: Maybe Dhall.Crypto.SHA256Digest , importType :: ImportType } deriving (Data, Generic) -- | Reference to an external resource data Import = Import { importHashed :: ImportHashed , importMode :: ImportMode } deriving (Data, Generic) instance Semigroup Directory where Directory components0 <> Directory components1 = Directory (components1 <> components0) instance Semigroup File where File directory0 _ <> File directory1 file = File (directory0 <> directory1) file instance Semigroup ImportType where Local prefix file0 <> Local Here file1 = Local prefix (file0 <> file1) Remote (URL { path = path0, ..}) <> Local Here path1 = Remote (URL { path = path0 <> path1, ..}) Local prefix file0 <> Local Parent file1 = Local prefix (file0 <> parent <> file1) Remote (URL { path = path0, .. }) <> Local Parent path1 = Remote (URL { path = path0 <> parent <> path1, .. }) import0 <> Remote (URL { headers = headers0, .. }) = Remote (URL { headers = headers1, .. }) where importHashed0 = Import (ImportHashed Nothing import0) Code headers1 = fmap (fmap (importHashed0 <>)) headers0 _ <> import1 = import1 instance Semigroup ImportHashed where ImportHashed _ importType0 <> ImportHashed hash importType1 = ImportHashed hash (importType0 <> importType1) instance Semigroup Import where Import importHashed0 _ <> Import importHashed1 code = Import (importHashed0 <> importHashed1) code parent :: File parent = File { directory = Directory { components = [ ".." ] }, file = "" }