Skip to content

Commit

Permalink
fix: support scoped CSS in templates by default (#336)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tarmil committed Nov 20, 2023
1 parent 40e3d78 commit 9a7481c
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 19 deletions.
28 changes: 14 additions & 14 deletions src/Bolero.Templating.Provider/Parsing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ let ParseAttribute (ownerNode: HtmlNode) (attr: HtmlAttribute) : Parsed =
| _ ->
WithVars parsed.Vars [Attr(name, Concat parsed.Expr)]

let rec ParseNode (node: HtmlNode) : Parsed =
let rec ParseNode (optimizeHtml: bool) (node: HtmlNode) : Parsed =
match node.NodeType with
| HtmlNodeType.Element ->
let name = node.Name
Expand All @@ -317,13 +317,9 @@ let rec ParseNode (node: HtmlNode) : Parsed =
|> Parsed.Concat
let children =
node.ChildNodes
|> Seq.map ParseNode
|> Seq.map (ParseNode optimizeHtml)
|> Parsed.Concat
if HasVars attrs || HasVars children then
(attrs, children)
||> Parsed.Map2 (fun attrs children ->
[Elt (name, attrs, children)])
else
if optimizeHtml && not (HasVars attrs || HasVars children) then
// Node has no vars, we can represent it as raw HTML for performance.
let rec removeComments (n: HtmlNode) =
if isNull n then () else
Expand All @@ -333,15 +329,19 @@ let rec ParseNode (node: HtmlNode) : Parsed =
| _ -> n.Remove()
removeComments nxt
NoVars [PlainHtml node.OuterHtml]
else
(attrs, children)
||> Parsed.Map2 (fun attrs children ->
[Elt (name, attrs, children)])
| HtmlNodeType.Text ->
// Using .InnerHtml and RawHtml to properly interpret HTML entities.
ParseText (node :?> HtmlTextNode).InnerHtml HoleType.Html
| _ ->
NoVars [] // Ignore comments

let ParseOneTemplate (nodes: HtmlNodeCollection) : Parsed =
let ParseOneTemplate (optimizeHtml: bool) (nodes: HtmlNodeCollection) : Parsed =
nodes
|> Seq.map ParseNode
|> Seq.map (ParseNode optimizeHtml)
|> Parsed.Concat

type ParsedTemplates =
Expand All @@ -351,7 +351,7 @@ type ParsedTemplates =
Nested: Map<string, Parsed>
}

let ParseDoc (filename: option<string>) (doc: HtmlDocument) : ParsedTemplates =
let ParseDoc (optimizeHtml: bool) (filename: option<string>) (doc: HtmlDocument) : ParsedTemplates =
let nested =
let templateNodes =
match doc.DocumentNode.SelectNodes("//template") with
Expand All @@ -366,12 +366,12 @@ let ParseDoc (filename: option<string>) (doc: HtmlDocument) : ParsedTemplates =
| null ->
failwith "Nested template must have an id" // at {n.Line}:{n.LinePosition}"
| id ->
let parsed = ParseOneTemplate n.ChildNodes
let parsed = ParseOneTemplate optimizeHtml n.ChildNodes
n.Remove()
(id, parsed)
)
|> Map.ofSeq
let main = ParseOneTemplate doc.DocumentNode.ChildNodes
let main = ParseOneTemplate optimizeHtml doc.DocumentNode.ChildNodes
{ Filename = filename; Main = main; Nested = nested }

/// Get the HTML document for the given type provider argument, either inline or from a file.
Expand All @@ -389,6 +389,6 @@ let GetDoc (fileOrContent: string) (rootFolder: string) : option<string> * HtmlD
Some (Path.GetRelativePath rootFolder fullPath), doc

/// Parse a type provider argument into a set of templates.
let ParseFileOrContent (fileOrContent: string) (rootFolder: string) : ParsedTemplates =
let ParseFileOrContent (fileOrContent: string) (rootFolder: string) (optimizeHtml: bool) : ParsedTemplates =
GetDoc fileOrContent rootFolder
||> ParseDoc
||> ParseDoc optimizeHtml
12 changes: 7 additions & 5 deletions src/Bolero.Templating.Provider/Provider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,20 @@ type Template (cfg: TypeProviderConfig) as this =

do try
let templateTy = ProvidedTypeDefinition(thisAssembly, rootNamespace, "Template", None, isErased = false)
let sp = ProvidedStaticParameter("pathOrHtml", typeof<string>)
sp.AddXmlDoc("The path to an HTML file, or an HTML string directly.")
templateTy.DefineStaticParameters([sp], fun typename pars ->
let pathOrHtmlParam = ProvidedStaticParameter("pathOrHtml", typeof<string>)
pathOrHtmlParam.AddXmlDoc("The path to an HTML file, or an HTML string directly.")
let optimizeHtmlParam = ProvidedStaticParameter("optimizePlainHtml", typeof<bool>, false)
optimizeHtmlParam.AddXmlDoc("Optimize the rendering of HTML segments that don't contain any holes. Warning: this is incompatible with the use of CSS scopes.")
templateTy.DefineStaticParameters([pathOrHtmlParam; optimizeHtmlParam], fun typename pars ->
match pars with
| [| :? string as pathOrHtml |] ->
| [| :? string as pathOrHtml; :? bool as optimizeHtml |] ->
let ty, _ =
cache.GetOrAdd(pathOrHtml, fun key ->
let asm = ProvidedAssembly()
let ty = ProvidedTypeDefinition(asm, rootNamespace, typename, Some typeof<TemplateNode>,
isErased = false,
hideObjectMethods = true)
let content = Parsing.ParseFileOrContent pathOrHtml cfg.ResolutionFolder
let content = Parsing.ParseFileOrContent pathOrHtml cfg.ResolutionFolder optimizeHtml
CodeGen.Populate ty content
asm.AddTypes([ty])
let fileWatcher = content.Filename |> Option.map (watchFileChanges key)
Expand Down

0 comments on commit 9a7481c

Please sign in to comment.