2023-07-22 15:48:00 +02:00
|
|
|
-- | `App.HomeInterface` presents the website and its features.
|
|
|
|
module App.HomeInterface where
|
2023-07-22 12:38:56 +02:00
|
|
|
|
|
|
|
import Prelude
|
|
|
|
|
2023-07-22 15:48:00 +02:00
|
|
|
import Control.Alt ((<|>))
|
|
|
|
import Control.Lazy (defer)
|
2023-07-23 14:06:09 +02:00
|
|
|
import Data.Array (many, length, snoc, last)
|
2023-07-22 15:48:00 +02:00
|
|
|
import Data.Either (Either(..))
|
2023-07-23 03:29:26 +02:00
|
|
|
import Data.Foldable (fold, foldl)
|
2023-07-22 15:48:00 +02:00
|
|
|
import Data.Maybe (Maybe(..))
|
2023-07-23 03:29:26 +02:00
|
|
|
import Data.Array.NonEmpty as NonEmpty
|
2023-07-22 14:58:52 +02:00
|
|
|
import Data.String.CodeUnits as CU
|
2023-07-23 14:06:09 +02:00
|
|
|
import Data.String as S -- length
|
2023-07-22 15:48:00 +02:00
|
|
|
-- import Data.String.Regex as R
|
|
|
|
-- import Data.String.Regex.Flags as RF
|
2023-07-23 03:29:26 +02:00
|
|
|
import Data.Tuple (Tuple(..))
|
2023-07-22 15:48:00 +02:00
|
|
|
import Effect.Aff.Class (class MonadAff)
|
|
|
|
import Effect (Effect)
|
|
|
|
import Halogen as H
|
|
|
|
import Halogen.HTML as HH
|
|
|
|
-- import Halogen.HTML.Events as HE
|
|
|
|
import Halogen.HTML.Properties as HP
|
|
|
|
import Parsing
|
|
|
|
import Parsing.Combinators as PC
|
2023-07-23 03:29:26 +02:00
|
|
|
import Parsing.Combinators.Array (many1)
|
2023-07-22 15:48:00 +02:00
|
|
|
import Parsing (Parser, runParser)
|
|
|
|
import Parsing.String
|
|
|
|
import Parsing.String.Basic
|
2023-07-22 12:38:56 +02:00
|
|
|
import Parsing.String.Basic (alphaNum, letter)
|
2023-07-22 15:48:00 +02:00
|
|
|
import Parsing.String (char, string, eof)
|
|
|
|
-- import TryPureScript (h1, h3, p, text, render, code)
|
|
|
|
import Bulma (h1, h3, p, text, code)
|
|
|
|
import Bulma as Bulma
|
|
|
|
|
|
|
|
type Input = Unit
|
|
|
|
data Action = UpdateStuff String
|
|
|
|
|
|
|
|
data Query a = DoNothing a
|
|
|
|
type Output = Unit
|
|
|
|
type Slot = H.Slot Query Output
|
|
|
|
|
|
|
|
type State = { stuff :: String }
|
|
|
|
|
|
|
|
component :: forall m. MonadAff m => H.Component Query Input Output m
|
|
|
|
component =
|
|
|
|
H.mkComponent
|
|
|
|
{ initialState
|
|
|
|
, render
|
|
|
|
, eval: H.mkEval $ H.defaultEval
|
|
|
|
{ handleAction = handleAction
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
handleAction :: forall m. MonadAff m => Action -> H.HalogenM State Action () Output m Unit
|
|
|
|
handleAction = case _ of
|
|
|
|
UpdateStuff val -> H.modify_ _ { stuff = val }
|
|
|
|
|
|
|
|
initialState :: forall input. input -> State
|
|
|
|
initialState _ = { stuff: "" }
|
|
|
|
|
|
|
|
render :: forall m. State -> H.ComponentHTML Action () m
|
|
|
|
render state
|
|
|
|
= HH.div_ $
|
|
|
|
[ Bulma.hero_danger "A simple input" "Nothing much to see"
|
|
|
|
, Bulma.section_small $
|
|
|
|
[ h1 "Examples of domain parsing in Purescript"
|
2023-07-23 14:06:09 +02:00
|
|
|
] <> test_domains [ "ex.net"
|
|
|
|
, "e-x.net"
|
|
|
|
, "way-too-long--way-too-long--way-too-long--way-too-long--way-too-long.net"
|
|
|
|
, "way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.net"
|
|
|
|
, "e-.net"
|
|
|
|
, "-x.net"
|
|
|
|
, "truc-blah.example.com"
|
|
|
|
, "te.s-t.net"
|
|
|
|
, "example.com"
|
|
|
|
]
|
2023-07-22 15:48:00 +02:00
|
|
|
, Bulma.section_small [ render_stuff ]
|
2023-07-23 14:06:09 +02:00
|
|
|
]
|
2023-07-22 15:48:00 +02:00
|
|
|
where
|
|
|
|
-- Some helpers.
|
|
|
|
title = Bulma.h3
|
|
|
|
p = Bulma.p
|
|
|
|
b x = Bulma.column_ [ Bulma.box x ]
|
|
|
|
|
|
|
|
render_stuff = Bulma.columns_ [ b [ title "stuff"
|
|
|
|
, stuff_input
|
|
|
|
]
|
|
|
|
, b [ title "result"
|
|
|
|
, p $ case runParser state.stuff parse_stuff of
|
|
|
|
Left _ -> "NOT OKAY"
|
|
|
|
Right _ -> "OKAY"
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
stuff_input
|
|
|
|
= Bulma.box_input "stuff" "stuff" "stuff"
|
|
|
|
UpdateStuff
|
|
|
|
state.stuff
|
|
|
|
true
|
|
|
|
should_be_disabled
|
|
|
|
should_be_disabled = (if true then (HP.enabled true) else (HP.disabled true))
|
|
|
|
|
|
|
|
-- test_domains :: Array String -> _
|
|
|
|
test_domains doms = fold $ map tests_on_domain doms
|
2023-07-23 14:06:09 +02:00
|
|
|
|
2023-07-22 15:48:00 +02:00
|
|
|
-- tests_on_domain :: String -> _
|
|
|
|
tests_on_domain d
|
2023-07-23 03:29:26 +02:00
|
|
|
= [ Bulma.strong $ d <> " -> [ldhstr, label, subdomain, domain]"
|
2023-07-23 14:06:09 +02:00
|
|
|
, p $ d <> " : ldhstr : " <> (show $ runParser d ldhstr)
|
|
|
|
, p $ d <> " : label : " <> (show $ runParser d label)
|
|
|
|
, p $ d <> " : subdomain : " <> (show $ runParser d subdomain)
|
|
|
|
, p $ d <> " : domain : " <> (show $ runParser d domain)
|
2023-07-22 15:48:00 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
aye :: Parser String Char
|
|
|
|
aye = defer \_ -> char 'a' *> aye
|
|
|
|
|
|
|
|
ayebee :: Parser String Boolean
|
|
|
|
ayebee = do
|
|
|
|
_ <- char 'a'
|
|
|
|
b <- char 'b' <|> char 'B'
|
|
|
|
pure (b == 'B')
|
|
|
|
|
|
|
|
parse_stuff :: Parser String Boolean
|
|
|
|
parse_stuff = do
|
2023-07-23 03:29:26 +02:00
|
|
|
void $ label
|
2023-07-22 15:48:00 +02:00
|
|
|
void $ eof
|
|
|
|
pure true
|
|
|
|
|
2023-07-22 12:38:56 +02:00
|
|
|
|
2023-07-23 03:29:26 +02:00
|
|
|
|
|
|
|
-- From RFC 1035: <domain> ::= <subdomain> | " "
|
2023-07-22 12:38:56 +02:00
|
|
|
domain :: Parser String String
|
2023-07-23 14:06:09 +02:00
|
|
|
domain = PC.try (string " ") <|> sub_eof
|
2023-07-22 14:58:52 +02:00
|
|
|
|
|
|
|
sub_eof :: Parser String String
|
|
|
|
sub_eof = do
|
2023-07-23 14:06:09 +02:00
|
|
|
sub <- subdomain
|
|
|
|
-- TODO: optional "." at the end?
|
2023-07-22 14:58:52 +02:00
|
|
|
eof
|
|
|
|
pure sub
|
2023-07-22 12:38:56 +02:00
|
|
|
|
2023-07-23 03:29:26 +02:00
|
|
|
-- From RFC 1035: <subdomain> ::= <label> | <subdomain> "." <label>
|
2023-07-22 12:38:56 +02:00
|
|
|
subdomain :: Parser String String
|
2023-07-23 14:06:09 +02:00
|
|
|
subdomain = defer \_ -> sub_point_label <|> label
|
2023-07-22 12:38:56 +02:00
|
|
|
|
2023-07-22 14:58:52 +02:00
|
|
|
sub_point_label :: Parser String String
|
|
|
|
sub_point_label = do
|
|
|
|
lab <- label
|
2023-07-23 14:06:09 +02:00
|
|
|
point <- string "."
|
|
|
|
sub <- defer \_ -> subdomain
|
|
|
|
let result = lab <> point <> sub
|
|
|
|
if S.length result > 255
|
|
|
|
then fail $ "domain length is > 255 bytes (" <> show (S.length result) <> ")"
|
|
|
|
else pure result
|
2023-07-22 12:38:56 +02:00
|
|
|
|
2023-07-23 03:29:26 +02:00
|
|
|
-- From RFC 1035: <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
|
2023-07-22 14:58:52 +02:00
|
|
|
label :: Parser String String
|
2023-07-23 14:06:09 +02:00
|
|
|
label = let_then_str_then_alpha
|
2023-07-22 14:58:52 +02:00
|
|
|
where
|
|
|
|
let_then_str_then_alpha :: Parser String String
|
|
|
|
let_then_str_then_alpha = do
|
|
|
|
l <- letter
|
2023-07-23 14:06:09 +02:00
|
|
|
s <- many let_dig_hyp
|
|
|
|
case last s of
|
|
|
|
Nothing -> pure $ CU.singleton l
|
|
|
|
Just last_char -> case runParser (CU.singleton last_char) alphaNum of
|
|
|
|
Left _ -> fail $ "Label is wrong: last char is '" <> (CU.singleton last_char) <> "' which isn't an alphanum"
|
|
|
|
Right _ -> if length s > 62 -- Remember: we already did read a letter (l).
|
|
|
|
then fail $ "Label is larger than expected (max 63 characters, current: " <> show (1 + length s) <> ")"
|
|
|
|
else pure $ CU.singleton l <> CU.fromCharArray (foldl (\acc x -> snoc acc x) [] s)
|
2023-07-22 12:38:56 +02:00
|
|
|
|
2023-07-23 03:29:26 +02:00
|
|
|
-- From RFC 1035: <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
|
2023-07-22 12:38:56 +02:00
|
|
|
ldhstr :: Parser String String
|
2023-07-23 03:29:26 +02:00
|
|
|
ldhstr = PC.try ldh_then_str <|> just_ldh
|
2023-07-22 14:58:52 +02:00
|
|
|
where
|
2023-07-23 03:29:26 +02:00
|
|
|
just_ldh :: Parser String String
|
|
|
|
just_ldh = char_to_string let_dig_hyp
|
|
|
|
|
|
|
|
ldh_then_str :: Parser String String
|
|
|
|
ldh_then_str = do
|
2023-07-22 14:58:52 +02:00
|
|
|
ldh <- let_dig_hyp
|
2023-07-22 15:48:00 +02:00
|
|
|
str <- defer \_ -> ldhstr
|
2023-07-22 14:58:52 +02:00
|
|
|
pure $ CU.singleton ldh <> str
|
|
|
|
|
2023-07-23 03:29:26 +02:00
|
|
|
-- From RFC 1035: <let-dig-hyp> ::= <let-dig> | "-"
|
2023-07-22 14:58:52 +02:00
|
|
|
-- Either a Letter, Digital or an Hyphenation character.
|
2023-07-22 12:38:56 +02:00
|
|
|
let_dig_hyp :: Parser String Char
|
2023-07-23 03:29:26 +02:00
|
|
|
let_dig_hyp = let_dig <|> char '-'
|
|
|
|
|
|
|
|
-- From RFC 1035: <let-dig> ::= <letter> | <digit>
|
|
|
|
let_dig :: Parser String Char
|
2023-07-23 14:06:09 +02:00
|
|
|
let_dig = alphaNum
|
2023-07-22 12:38:56 +02:00
|
|
|
|
2023-07-22 14:58:52 +02:00
|
|
|
-- | Converting a single letter parser to a String parser.
|
2023-07-23 03:29:26 +02:00
|
|
|
char_to_string :: Parser String Char -> Parser String String
|
|
|
|
char_to_string p = do
|
2023-07-22 14:58:52 +02:00
|
|
|
a <- p
|
|
|
|
pure $ CU.singleton a
|
|
|
|
|
2023-07-23 03:29:26 +02:00
|
|
|
-- Not used currently.
|
|
|
|
hyp_then_string :: Parser String String
|
|
|
|
hyp_then_string = do
|
|
|
|
a <- char_to_string let_dig_hyp
|
|
|
|
b <- ldhstr
|
|
|
|
pure $ a <> b
|