summaryrefslogtreecommitdiff
path: root/Biz/Namespace.hs
blob: b9ef994dbc01a609a86e6249b252374d6cb0c566 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Biz.Namespace
  ( Namespace (..),
    Ext (..),
    fromPath,
    fromContent,
    fromHaskellModule,
    toPath,
    toHaskellModule,
    toSchemeModule,
    isCab,
  )
where

import Alpha
import qualified Data.Aeson as Aeson
import qualified Data.Char as Char
import qualified Data.List as List
import qualified Data.List.Split as List
import qualified Text.Regex.Applicative as Regex

data Ext = Hs | Scm | Nix | Md | Css | Py | Sh | Keys | Json | None | Rs
  deriving (Eq, Show, Generic, Aeson.ToJSON)

data Namespace = Namespace {path :: [String], ext :: Ext}
  deriving (Eq, Show, Generic, Aeson.ToJSON)

fromPath :: String -> String -> Maybe Namespace
fromPath bizRoot absPath =
  List.stripPrefix bizRoot absPath
    +> List.stripPrefix "/"
    +> Regex.match (Namespace </ rePath <* dot <*> reExt)

fromContent :: String -> Maybe Namespace
fromContent c = case Regex.findFirstInfix haskellModule c of
  Nothing -> Nothing
  Just (_, Namespace {..}, _) -> Just <| Namespace (filter (/= ".") path) ext
  where
    haskellModule =
      Namespace
        </ (Regex.string "\nmodule " *> Regex.many (name <|> dot))
        <*> pure Hs

toHaskellModule :: Namespace -> String
toHaskellModule (Namespace parts Hs) = joinWith "." parts
toHaskellModule (Namespace {..}) =
  panic <| "can't convert " <> show ext <> " to a Haskell module"

fromHaskellModule :: String -> Namespace
fromHaskellModule s = Namespace (List.splitOn "." s) Hs

toPath :: Namespace -> FilePath
toPath (Namespace parts ext) =
  joinWith "/" parts
    <> "."
    <> lowercase (show ext)

toSchemeModule :: Namespace -> String
toSchemeModule (Namespace parts Scm) = "(" ++ joinWith " " parts ++ ")"
toSchemeModule (Namespace {..}) =
  panic <| "can't convert " <> show ext <> " to a Scheme module"

dot :: Regex.RE Char String
dot = Regex.some <| Regex.sym '.'

name :: Regex.RE Char String
name =
  Regex.many (Regex.psym Char.isUpper)
    <> Regex.many (Regex.psym Char.isAlphaNum)

rePath :: Regex.RE Char [String]
rePath = Regex.many (name <* Regex.string "/" <|> name)

reExt :: Regex.RE Char Ext
reExt =
  Nix <$ Regex.string "nix"
    <|> Hs <$ Regex.string "hs"
    <|> Scm <$ Regex.string "scm"
    <|> Md <$ Regex.string "md"
    <|> Css <$ Regex.string "css"
    <|> Py <$ Regex.string "py"
    <|> Sh <$ Regex.string "sh"
    <|> Keys <$ Regex.string "pub"
    <|> Json <$ Regex.string "json"
    <|> Rs <$ Regex.string "rs"

-- | The cab dir is for temporary files and build outputs, not for source
-- inputs.
isCab :: FilePath -> Bool
isCab ('_' : _) = True
isCab fp = "_" `List.isInfixOf` fp