{-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors #-} {-# LANGUAGE TypeFamilyDependencies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE CPP #-} -- Compatibility with ghc8.2 module Html.Type.Internal where import GHC.TypeLits import GHC.Exts (Constraint) import Data.Proxy import Data.Type.Bool import Data.ByteString (ByteString) {-# DEPRECATED Acronym , Applet , Basefont , Big , Blink , Center , Command , Content , Dir , Font , Frame , Frameset , Isindex , Keygen , Listing , Marquee , Multicol , Noembed , Plaintext , Shadow , Spacer , Strike , Tt , Xmp , Nextid "This is an obsolete html element and should not be used." #-} -- | Data for declaring variables in a html document which will be compacted. data V (n :: Symbol) = V newtype One a = One a -- | Unique set of variables in a html document in the order of occurence. type Variables a = Dedupe (GetV a) -- | A compacted html documented with it's variables annoted as a list of Symbols. data CompactHTML (a :: [Symbol]) = MkCompactHTML ByteString [(Int, ByteString)] deriving Show type family GetV a :: [Symbol] where GetV (a # b) = Append (GetV a) (GetV b) GetV ((a :@: b) c) = Append (GetV b) (GetV c) GetV (a := b) = GetV b GetV (Maybe a) = GetV a GetV [a] = GetV a GetV (Either a b) = Append (GetV a) (GetV b) GetV (V v) = '[v] GetV x = '[] type family Reverse xs where Reverse xs = Reverse' xs '[] type family Reverse' xs ys where Reverse' (x':xs) ys = Reverse' xs (x':ys) Reverse' '[] ys = ys type family Dedupe xs :: [Symbol] where Dedupe (x ': xs) = x ': Dedupe (Delete x xs) Dedupe '[] = '[] type family Delete x xs :: [Symbol] where Delete x (x ': xs) = Delete x xs Delete x (y ': xs) = y ': Delete x xs Delete _ _ = '[] class ShowTypeList a where showTypeList :: [String] instance (ShowTypeList xs, KnownSymbol x) => ShowTypeList (x ': xs) where showTypeList = symbolVal (Proxy @ x) : showTypeList @ xs instance ShowTypeList '[] where showTypeList = [] -- | The data type of all html elements and the kind of elements. data Element = DOCTYPE | A | Abbr | Acronym | Address | Applet | Area | Article | Aside | Audio | B | Base | Basefont | Bdi | Bdo | Bgsound | Big | Blink | Blockquote | Body | Br | Button | Canvas | Caption | Center | Cite | Code | Col | Colgroup | Command | Content | Data | Datalist | Dd | Del | Details | Dfn | Dialog | Dir | Div | Dl | Dt | Element | Em | Embed | Fieldset | Figcaption | Figure | Font | Footer | Form | Frame | Frameset | H1 | H2 | H3 | H4 | H5 | H6 | Head | Header | Hgroup | Hr | Html | I | Iframe | Image | Img | Input | Ins | Isindex | Kbd | Keygen | Label | Legend | Li | Link | Listing | Main | Map | Mark | Marquee | Math | Menu | Menuitem | Meta | Meter | Multicol | Nav | Nextid | Nobr | Noembed | Noframes | Noscript | Object | Ol | Optgroup | Option | Output | P | Param | Picture | Plaintext | Pre | Progress | Q | Rp | Rt | Rtc | Ruby | S | Samp | Script | Section | Select | Shadow | Slot | Small | Source | Spacer | Span | Strike | Strong | Style | Sub | Summary | Sup | Svg | Table | Tbody | Td | Template | Textarea | Tfoot | Th | Thead | Time | Title | Tr | Track | Tt | U | Ul | Var | Video | Wbr | Xmp data Attribute = RoleA | AriaActivedescendantA | AriaAtomicA | AriaAutocompleteA | AriaBusyA | AriaCheckedA | AriaControlsA | AriaDescribedbyA | AriaDisabledA | AriaDropeffectA | AriaExpandedA | AriaFlowtoA | AriaGrabbedA | AriaHaspopupA | AriaHiddenA | AriaInvalidA | AriaLabelA | AriaLabelledByA | AriaLevelA | AriaLiveA | AriaMultilineA | AriaMultiselectableA | AriaOwnsA | AriaPosinsetA | AriaPressedA | AriaReadonlyA | AriaRelevantA | AriaRequiredA | AriaSelectedA | AriaSetsizeA | AriaSortA | AriaValuemaxA | AriaValueminA | AriaValuenowA | AriaValuetextA | AcceptA | AcceptCharsetA | AccesskeyA | ActionA | AllowfullscreenA | AllowpaymentrequestA | AlignA | AltA | AsyncA | AutocompleteA | AutofocusA | AutoplayA | AutosaveA | BgcolorA | BorderA | BufferedA | ChallengeA | CharsetA | CheckedA | CiteA | ClassA | CodeA | CodebaseA | ColorA | ColsA | ColspanA | ContentA | ContenteditableA | ContextmenuA | ControlsA | CoordsA | CrossoriginA | DataA | DatetimeA | DefaultA | DeferA | DirA | DirnameA | DisabledA | DownloadA | DraggableA | DropzoneA | EnctypeA | ForA | FormA | FormactionA | FormenctypeA | FormmethodA | FormnovalidateA | FormtargetA | HeadersA | HeightA | HiddenA | HighA | HrefA | HreflangA | HttpEquivA | IconA | IdA | IntegrityA | IsmapA | ItempropA | KeytypeA | KindA | LabelA | LangA | LanguageA | ListA | LongdescA | LoopA | LowA | ManifestA | MaxA | MaxlengthA | MediaA | MethodA | MinA | MinlengthA | MultipleA | MutedA | NameA | NonceA | NovalidateA | OpenA | OptimumA | PatternA | PingA | PlaceholderA | PosterA | PreloadA | RadiogroupA | ReadonlyA | ReferrerpolicyA | RelA | RequiredA | RevA | ReversedA | RowsA | RowspanA | SandboxA | ScopeA | ScopedA | SeamlessA | SelectedA | ShapeA | SizeA | SizesA | SlotA | SpanA | SpellcheckA | SrcA | SrcdocA | SrclangA | SrcsetA | StartA | StepA | StyleA | SummaryA | TabindexA | TargetA | TitleA | TranslateA | TypeA | TypemustmatchA | UsemapA | ValueA | WidthA | WrapA -- | We need efficient cons, snoc and append. This API has cons(O1) -- and snoc(O1) but append(On). Optimal would be a FingerTree. data List = List [Symbol] Symbol type family (<|) s t :: List where (<|) l ('List (s ': ss) r) = 'List (AppendSymbol l s ': ss) r (<|) l ('List '[] r) = 'List '[] (AppendSymbol l r) type family (|>) t s :: List where (|>) ('List ss r) rr = 'List ss (AppendSymbol r rr) type family (><) t1 t2 :: List where (><) ('List ss r) ('List (s ': ss2) r2) = 'List (Append ss (AppendSymbol r s ': ss2)) r2 (><) ('List ss r) ('List '[] r2) = 'List ss (AppendSymbol r r2) type OpenTag e = AppendSymbol "<" (AppendSymbol (ShowElement e) ">") type CloseTag e = AppendSymbol "" (AppendSymbol (ShowElement e) ">") -- | Flatten a document into a type list of tags. type family ToList a :: List where ToList (a # b) = ToList a >< ToList b ToList ((a :@: ()) ()) = 'List '[] (If (HasContent (GetEInfo a)) (AppendSymbol (OpenTag a) (CloseTag a)) (OpenTag a)) ToList ((a :@: b) ()) = AppendSymbol "<" (ShowElement a) <| ToList b |> If (HasContent (GetEInfo a)) (AppendSymbol ">" (CloseTag a)) ">" ToList ((a :@: ()) b) = OpenTag a <| ToList b |> CloseTag a ToList ((a :@: b) c) = (AppendSymbol "<" (ShowElement a) <| ToList b) >< (">" <| ToList c |> CloseTag a) ToList (a := ()) = 'List '[] (AppendSymbol " " (ShowAttribute a)) ToList (a := b) = AppendSymbol " " (AppendSymbol (ShowAttribute a) "=\"") <| ToList b |> "\"" ToList () = 'List '[] "" ToList (Proxy x) = 'List '[] x ToList x = 'List '[""] "" newtype (:=) (a :: Attribute) b = AT b -- | Check whether `b` is a valid child of `a`. type a ?> b = Check Element a b -- | Check whether `a` is a valid attribute and `b` is a valid child of `p`. type (>) p a b = (Check Attribute p a, Check Element p b) type family Check f a b :: Constraint where Check _ _ () = () Check _ _ (Raw _) = () Check f a (b # c) = (Check f a b, Check f a c) Check f a (Maybe b) = Check f a b Check f a (Either b c) = (Check f a b, Check f a c) Check f a (b -> c) = TypeError (ShowType a :<>: Text " can't contain a function.") Check Element a ((b :@: _) _) = MaybeTypeError a b (CheckContentCategory (EInfoContent (GetEInfo a)) (SingleElement b ': EInfoCategories (GetEInfo b))) Check Element a (f ((b :@: c) d)) = Check Element a ((b :@: c) d) Check Element a (f (b # c)) = Check Element a (b # c) Check Element a b = CheckString a b Check Attribute a (b := _) = If (Elem a (AInfoElements (GetAInfo b)) || Null (AInfoElements (GetAInfo b))) (() :: Constraint) (TypeError (ShowType b :<>: Text " is not a valid attribute of " :<>: ShowType a)) Check Attribute _ b = TypeError (ShowType b :<>: Text " is not an attribute.") -- | Combine two elements or attributes sequentially. -- -- >>> i_ () # div_ () --
-- -- >>> i_A (A.id_ "a" # A.class_ "b") "c" -- c data (#) a b = (:#:) a b {-# INLINE (#) #-} (#) :: a -> b -> a # b (#) = (:#:) infixr 5 # -- | Type synonym for elements without attributes. type (>) a b = (:@:) a () b infixr 6 > -- | Decorate an element with attributes and descend to a valid child. -- It is recommended to use the predefined elements. -- -- >>> WithAttributes (A.class_ "bar") "a" :: ('Div :@: ('ClassA := String)) String -- -- -- >>> div_A (A.class_ "bar") "a" -- -- -- >>> div_ "a" --