snapframework / heist Goto Github PK
View Code? Open in Web Editor NEWAn xhtml-based templating engine, allowing Haskell functions to be bound to XML tags.
Home Page: http://snapframework.com/
License: BSD 3-Clause "New" or "Revised" License
An xhtml-based templating engine, allowing Haskell functions to be bound to XML tags.
Home Page: http://snapframework.com/
License: BSD 3-Clause "New" or "Revised" License
snaplet-stripe
currently doesn't build with the latest version of heist
. I'd like to fix that, but I'm not a heist
user. Unfortunately, there is no documentation that lets me learn where hcCompiledSplices
has gone, and what I should be doing instead. This problem (and future problems) could be reduced if there was a Changelog
document, which would document API changes, and ideally how one can fix parts that have changed.
Example:
Try putting the following regular html code (imagine the HTML braces there; github has issues with them)
<input type='text' value='This is just a value that has $ in it. But this part will never show, as $ will trigger attribute substitution and remove this entire part of this text'>
The resulting input node will only contain:
"This is just a value that has " in its value attribute.
Using an attribute substitution in an apply tag leads to a stack overflow in the latest version of snap / heist.
Two Heist templates which produce the issue are:
attrsubtest1.tpl:
<content />
attrsubtest2.tpl:
<bind tag="test">asdf</bind>
<apply template="attrsubtest1">
<a href="${test}">link</a>
</apply>
And the output when requesting attrsubtest2.tpl is:
A web handler threw an exception. Details:
stack overflow
I built up a [Node]
manually using only xmlhtml
. Let's refer to it as myNodes
. If I do
main = BC8.putStrLn $ Blaze.toByteString $ renderXmlFragment UTF8 myNodes
Then it renders fine. But, it is just an XML fragment, so I need to splice this into a template. This seems like it should be simple. It's a constant [Node]
. So, I tried this:
main = do
let heist = hcTemplateLocations .~ [ loadTemplates "templates" ]
$ hcNamespace .~ ""
$ hcCompiledSplices .~ ("report" ## return (yieldPure (nodeSplice (const $ myNodes) ())))
$ emptyHeistConfig
heistState <- do
res <- runEitherT $ initHeist heist
case res of
Left err -> error $ unlines err
Right a -> return a
builder <- maybe (error "oops") fst $
renderTemplate heistState "report"
BC8.putStrLn . Blaze.toByteString $ builder
But now I get this:
sheets: style:style cannot contain child elements or comments
Which seems bad because it's an exception thrown from pure code in xmlhtml
(src/Text/XmlHtml/HTML/Render.hs). Also, if I just remove the line for using compiled splices, then it runs fine (but without replacing <report/>
of course). So, something in heist is messing up the rendering of the otherwise alright node list. In case this is helpful:
Correct rendering of myNodes
:
<office:automatic-styles><style:style style:name='basic-column-style' style:family='table-column'><style:table-column-properties fo:break-before='auto' style:column-width='0.9in'/></style:style><style:style style:name='basic-row-style' style:family='table-row'><style:table-row-properties fo:break-before='auto' style:row-height='0.178in' style:use-optimal-row-height='true'/></style:style><style:style style:name='basic-table-style' style:family='table' style:master-page-name='Default'><style:table-properties table:display='true' style:writing-mode='lr-tb'/></style:style><style:style style:name='foo11' style:family='table-cell'><style:table-cell-properties fo:border-top='none' fo:border-bottom='none' fo:border-left='none' fo:border-right='none'/></style:style></office:automatic-styles><office:body><office:spreadsheet><table:table table:name='Sheet1' table:style-name='basic-table-style'><table:table-column table:number-columns-repeated='1' table:style-name='basic-column-style'/><table:table-row table:style-name='basic-row-style'><table:table-cell table:style-name='foo11'><text:p>Hello There</text:p></table:table-cell></table:table-row></table:table></office:spreadsheet></office:body>
report.tpl
<?xml version="1.0" encoding="UTF-8"?>
<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2">
<office:scripts/>
<office:font-face-decls>
<style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="DejaVu Sans" svg:font-family="'DejaVu Sans'" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Droid Sans Fallback" svg:font-family="'Droid Sans Fallback'" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="FreeSans" svg:font-family="FreeSans" style:font-family-generic="system" style:font-pitch="variable"/>
</office:font-face-decls>
<report/>
</office:document-content>
The current version on hackage, 1.1.0.1
doesn't support base 4.14. Any plans to make a point release with the bounds bumped?
Consider this .tpl file:
<html>
<head>
<apply template="meta"/>
</head>
</html>
With this meta.tpl file:
<meta http-equiv='content-type' content='text/html; charset=utf-8' />
<meta name='robots' content='noarchive' />
Then this is the result:
<html>
<head>
<meta http-equiv='content-type' content='text/html; charset=utf-8' />
<meta name='robots' content='noarchive' />
</head>
</html>
Note the misalignment of the second line.
Can this be fixed? (I like my websites to have beautiful HTML.)
So I'm trying to use this library on it's own (without Snap's heist snaplet), but it doesn't appear to be a simple process to create a HeistConfig
value. Perhaps it would be useful to demonstrate such an example?
By running
nix-prefetch-url http://hackage.haskell.org/package/heist-1.0.1.0/revision/6.cabal
I can see the store path to the heist.cabal that, in turn, seems to be old. (The above link seems to show it, too.)
There is aeson upper bound < 1.2 while here on the github it seems to be < 1.3. Also hackage seems to refer to old version, see heist on hackage.
The nixpkgs seems to refer to heist-1.0.1.0 and revision 6. See the lines around line 98640 in
hackage-packages.
There is possibly some other revisions/changes made after aeson upper bound change? If so, it would mean that those changes are also not available at nixos.
Any chances to get a new version 1.0.1.1 that would certainly have the latest changes?
I can't see which revs correspond to releases past 0.5.0.1.
We have a MonadReader
-like typeclass that we'd like to implement for RuntimeSplice m
. Currently this is not possible, since you can't implement local
. One option is to expose the RuntimeSplice
constructor and unRS
deconstructor. Then we could do something like:
instance OurReader m => OurReader (RuntimeSplice m) where
ourAsk = lift ourAsk
ourLocal f = RuntimeSplice . ourLocal f . unRT
Another option is to provide an instance of MonadTransControl
for RuntimeSplice. This could be used to write ourLocal
and would also allow use of the functions from lifted-base, like catch
.
I could send a pull request for either option, if you let me know which (if any) you prefer.
mtl-2.2.1 has Except
Previous versions of mtl <= 2.2.0.1 do not.
MonadError in Types requires Except, and therefore the lower bound of 2.0
currently in Heist is unsuitable.
Currently testing with a lower bound of 2.2.1
and some other bounds modifications as part of a full Snap app.
So, when I use heist for XML (or HTML, but I assume that it probably leads to correct behaviors in that case), the end of the resulting document looks like this:
</office:body> </office:document-content>
When I run this file through xmllint, I get:
andrew@webapps-test:~/projects/sheets$ xmllint --format sheet.xml
sheet.xml:6: parser error : Extra content at the end of the document
</table:table></office:spreadsheet></office:body> </office:document-content>
^
Other linters give similar complaints. This is because you aren't supposed to have any content after closing the root tag in an XML document. Is there something that I have missed (ie- rendering it the wrong way), or is this case not correctly handled?
Maybe I don't understand the point of bindJson
at all, but I expected the following to be possible:
Bind a JSON splice, for example using:
bindSplice "foo" (bindJson $ object [ "bar" .= 1, "baz" .= 2 ])
(having object
and (.=)
imported from Data.Aeson
, and then in the template using
<foo><value/></foo>
but this only produces an error message saying var
should be specified for value
. While the docs say that this is the intended behavior, I do not understand the rationale for this limitation and would like to see it lifted.
I haven't released 0.12 yet, but you can find it at the expected place.
Failed to install heist-0.11.1
Last 10 lines of the build log ( /Users/bryano/Downloads/t/.cabal-sandbox/logs/heist-0.11.1.log ):
In the first argument of `numToText', namely `n'
In the second argument of `($)', namely `numToText n'
In the expression: txt $ numToText n
src/Heist/Splices/Json.hs:158:40:
Couldn't match expected type `Number'
with actual type `scientific-0.3.2.1:Data.Scientific.Scientific'
In the first argument of `numToText', namely `n'
In the second argument of `($)', namely `numToText n'
In the expression: goText $ numToText n
I just noticed this, and I kind of prefer this behavior, but there's no way to switch HeistState
out of preprocessing mode.
So I've been trying to figure out why a simple template is taking a very long time to render (nearly a second). I realized my heist config was trying to compile the templates - I've prevented that.
However it's still taking 0.2s, upon further investigation if I add a bunch of large templates into my templates directory - the performance drops. I'm not rendering those templates so I don't see why any processing is being done on them.
Here is my function I use to render:
renderHeistTemplatePath :: TemplateName -> HeistBind -> IO (Either Text Text)
renderHeistTemplatePath fileName hsBinding = do
let emptyI = return () :: MapSyntax Text (I.Splice IO)
let emptyC = return () :: MapSyntax Text (HeistCom.Splice IO)
let emptyA = return () :: MapSyntax Text (AttrSplice IO)
let templateLocations = [Heist.loadTemplates "templates/"]
let spliceConfig = SpliceConfig emptyI emptyI emptyC emptyA templateLocations (\_ -> False):: SpliceConfig IO
heist <- Heist.initHeist (HeistConfig spliceConfig "" True)
case heist of
Right heist' -> do
rendered <- I.renderTemplate (hsBinding heist') $ convertString fileName
case (rendered) of
Just (builder, _) -> return . return . convertString $ toLazyByteString builder
Nothing -> return . Left $ "Heist render error. No further information"
Left a -> return . Left . convertString . show $ a
Any ideas would greatly be appreciated.
There's a problem with how compiled Heist loads templates in compileTemplates'. It processes all the templates, including ones starting with an underscore, even though those aren't meant to be used directly. This causes problems when namespaces are also used, since subtemplates potentially have tags that are only bound with withSplices.
https://github.com/kaol/heist/tree/nsbindcall has the fix and https://github.com/kaol/heist/tree/nsbindcall-test has a test for calling underscored template with namespaces. The new test should work with master and my branch but the code in master fails with the added underscored template in the nsbinderr test.
HTML comments have the following format:
<!-- foo -->
This is fine, however, the number of -
characters used is not correctly specified in Heist. HTML does not make a distinction between <!--
and <!---
or -->
and ------>
. Any hyphens after the opening two and preceding the ending two are not significant. Heist will throw a parse error in this situation.
Heist won't compile against the latest version of the errors package. If there is a chance, could you please release a quick update that remedies this issue? The error message I get trying to compile Heist is:
src/Heist.hs:140:30:
Not in scope: type constructor or class `EitherT'
Perhaps you meant one of these:
`Either' (imported from Prelude),
`EitherR' (imported from Control.Error),
`EitherRT' (imported from Control.Error)
This requires hashable < 1.2 but it's up to 1.2.0.2 now. It compiles fine with that requirement dropped.
My use case was something like:
<apply template="path/to/outer"><apply template="path/to/inner"/></apply>
Which causes heist to look for "inner" in /path/to/path/to/inner, because there is no leading /. I have no opinion on whether this behavior is correct or not, but it did surprise me as a newbie. It would help even out the learning curve if file-not-found conditions issued some kind of warning message (or maybe I just don't know how to turn warnings on).
I'm parsing YAML into a Aeson.Value and passing it straight to the template using bindJson
, for using like this (tags
would be a YAML field with list value):
<with var="tags">
<a title="Tag" class="px-1 bg-gray-100 rounded">
<value />
</a>
</with>
This however doesn't work when the YAML has no fields named "tag"; Heist throws: expression error: can't find "tags" in JSON object (<with> tag)
I'd like to be able to specify a "else" case to render if there is no such field, based on the similar behaviour if the IfElse splice, i.e.
<with var="tags">
<a title="Tag" class="px-1 bg-gray-100 rounded">
<value />
</a>
<else />
<p>This note is not tagged</p> <!-- Can also be empty -->
</with>
What do you folks think of this feature? It may be extended to <value>
and <snippet>
as well.
I built a template for establishing an RSS feed at https://github.com/justindthomas/blog/blob/master/snaplets/heist/templates/rss.xtpl
Despite trying to direct Snap to render that as "application/rss+xml", it insists on removing the ?xml directives and prepending a at the top (see https://ser.endipito.us/rss.xml for an example). That breaks all RSS readers that I've tried (and the validator at https://validator.w3.org/feed/ just aborts immediately when the document is pasted in, saying it's a web page, not an RSS feed).
RSS 2.0 specifies that there should/can be no DOCTYPE. Any mechanism for dropping that from the parser should solve this issue. Also refraining from stripping the ?xml directives for xtpl files would be nice.
If you bind an interpreted splice (e.g. ("foo", textSplice "bar")
) and use it in an attribute, it doesn't work. The following template:
<foo/>
<a class="${foo}">bla</a>
will render as
bar
<a class="${foo}">bla</a>
Even nastier, the following template
<bind tag=bar><foo/></bind>
<a class="${bar}">bla</a>
will render as
<a class>bla</a>
This is because the bind expands to <foo/>
at compile time, and heist then takes the text content, which is empty.
The right fix seems to be to compile attributes to Chunks as well, but that looked like a rather invasive fix. Any ideas?
To my knowledge, heist
doesn't provide a way to enable/disable minimized attributes. I saw a reddit question where someone gave this example of a template they had written:
<select>
<for-stylesheets>
<if-equal a="${key}" b="${active-stylesheet}">
<option value="${key}" selected><name/></option>
</if-equal>
<if-not-equal a="${key}" b="${active-stylesheet}">
<option value="${key}"><name/></option>
</if-not-equal>
</for-stylesheets>
</select>
What's bad is that the if-equal
and if-not-equal
splices only differ in whether the option
element has the selected
attribute enabled. Ideally, it would be possible to write something like this:
<option value="${key}" selected="${is-selected}"><name/></option>
Except that this makes selected
appear in all cases. Is there a workaround for this (possibly one that generates non-compliant HTML5 that all browsers still understand)?
I was not able to dig the exact source of this error in Heist code, but if I put a $ value within a bound splice and use it as an attribute substitute, the attribute substitution process seems to continue recursion into the initial substitute and further try to replace the inner text. I was unable to stop this using stopRecursion.
For example:
sampleSplice = do
stopRecursion
textSplice ("Here is a text splice with $ in it. But this part will not be seen, as Heist will keep recursing and look to replace anything after $.")
I'm using interpreted splices and trying to add templates to the HeistState
at runtime. However, I can't get any of the templates to use the default splices. What I have right now will render the template exactly as it is loaded, without applying bind
or apply
tags.
The relevant parts of my code (I think) are the heistConfig
function and the line that reads mrendered <- I.renderTemplate newHs title
. I will post it all in case it is somehow helpful. However, you will not be able to run this.
Let me know if I can do anything to clarify the issue further.
{-# LANGUAGE ScopedTypeVariables #-}
module Microsite.Functions
( renderPage
) where
import Lens.Family (set)
import qualified Heist as H
import qualified Heist.Interpreted as I
import Heist (HeistConfig, HeistT, HeistState)
import qualified Microsite.Types as MS
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Control.Monad.Trans.Either (runEitherT)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.ByteString (ByteString)
import System.IO.Unsafe (unsafePerformIO)
import Text.XmlHtml (parseHTML, docContent)
import Blaze.ByteString.Builder as Blaze
renderPage :: forall m. MonadIO m => MS.Interface m -> MS.MicrositeId -> MS.ResourceName -> m (Either String ByteString)
renderPage interface theId name = do
markupText <- MS.loadResourceMarkup interface theId MS.Page name
let markupByteString = TE.encodeUtf8 markupText
hs <- liftIO (baseHeistState :: IO (HeistState m))
let res = parseHTML (MS.resourceNameToString name) markupByteString
case res of
Left errMsg -> return $ Left errMsg
Right document -> do
let nodes = docContent document
title = TE.encodeUtf8 $ MS.unResourceName name
newHs = I.addTemplate title nodes Nothing hs
mrendered <- I.renderTemplate newHs title
case mrendered of
Just (builder, _) -> return $ Right $ Blaze.toByteString builder
Nothing -> return $ Left "Something in heist messed up"
baseHeistState :: MonadIO m => IO (HeistState m)
baseHeistState = do
res <- runEitherT $ H.initHeist heistConfig
return $ either (error "heist state has broken in microsite") id res
heistConfig :: MonadIO m => HeistConfig m
heistConfig = set H.hcNamespace (T.pack "h") $
set H.hcInterpretedSplices H.defaultInterpretedSplices $
set H.hcErrorNotBound True $
H.emptyHeistConfig
Around line 660 at Text.Templating.Heist.Internal.hs
Both getDoc
and getXMLDoc
leverage parseHTML
from xmlhtml and I suspect getXMLDoc
is expected to use parseXML
.
Thanks.
Is there a reason pandoc isn't listed as a dependency?
This is causing heist
builds to fail over in nixpkgs. Without an official dependency on pandoc, cabal2nix
doesn't correctly set up an environment so heist tests can run.
I decided to open this issue instead of going directly for a PR so we can discuss the correct fix.
The namespace warning message gets triggered when the splice uses are not on top level but instead inside regular tags.
I've made a test demonstrating the issue at https://github.com/kaol/heist/tree/overzealous-namespace-warning-test
heist/fsLoad: [OK]
heist/renderNoName: [OK]
heist/doctype: [OK]
heist/attributeSubstitution: [OK]
heist/bindAttribute: [OK]
heist/markdown: [OK]
heist/pandoc: [Failed]
ERROR: user error (Pattern match failure in do expression at test/suite/Heist/Interpreted/Tests.hs:319:9-21)
heist/pandoc_div: [Failed]
ERROR: user error (Pattern match failure in do expression at test/suite/Heist/Interpreted/Tests.hs:319:9-21)
heist/title_expansion: [OK]
heist/textarea_expansion: [OK]
heist/div_expansion: [OK]
heist/bind_param: [OK]
heist/markdownText: [OK]
heist/apply: [OK]
heist/ignore: [OK]
heist/lookupTemplateContext: [OK]
heist/attrSpliceContext: [OK]
heist/json/values: [OK]
heist/json/object: [OK]
heist/renderXML: [Failed]
ERROR: user error (Pattern match failure in do expression at test/suite/Heist/Interpreted/Tests.hs:319:9-21)
Heist.Compiled.Tests:
compiled/simple: [OK]
compiled/people: [OK]
compiled/namespace1: [Failed]
namespace test 1
expected: Right "Alpha\naoeu\nBeta\n<h:foo aoeu='htns'>Inside h:foo</h:foo>\nEnd\n"
but got: Left ["Error rendering"]
compiled/namespace2: [Failed]
namespace test 2
expected: Right "Alpha\naoeu\nBeta\n<h:foo aoeu='htns'>Inside h:foo</h:foo>\nEnd\n"
but got: Left ["Error rendering"]
compiled/namespace3: [Failed]
This Heist code
<a href="" onclick="return false;" id="abt">About</a>
turns into this HTML
<a href onclick='return false;' id='abt'>About</a>
This is not good, because the W3 Validator spits out a warning about it:
Warning: Attribute href without an explicit value seen. The attribute may be dropped by IE7.
I want my HTML to pass all validations.
Can you make =""
not disappear?
It seems I cannot use nested JSON in heist templates. In the inner Json handling location, I can't access the outer Json's field.
Is this by design, or is simply a limitation of explodeTag
's current implementation?
All HTML entities found in my templates are being converted to the actual character (eg. &
becomes &
, ©
becomes ©
). For most characters, this doesn't matter a whole lot, but a raw ampersand causes HTML validation to fail.
Template source:
<p class="copyright">©2013 Company Name here</p>
Rendered document's source:
<p class='copyright'>©2013 Company Name here</p>
textSplice
cannot obviously be used to inject raw HTML (say, those coming from Pandoc rendered HTML) into heist template, as they will be automatically escaped.
One solution is to parse the raw HTML using Text.XmlHtml
but this is obviously both unnecessary and waste of CPU usage.
Does heist support injecting raw HTML?
A related question: if I'm to build HTML from some AST (say Pandoc AST), how does the performance of Text.XmlHtml
compare to others (such as blaze-html)?
When trying the following
<bind tag="foo">5</bind>
<fact><foo/></fact>
(here fact
is bound to factSplice
from the tutorial)
it seems that <foo/>
is not expanded before the splice is evaluated (which in this case leads to an exception).
Do we want to support the above example? If no, is there a way to do something similar with heist? In particular I'd like to bind some name
inside my code with bindString
and pass it to a splice.
If the first thing in a template is a bind-tag and that bind tag is followed by a whitespace then, for some reason, the whitespace is replaced by a numeric character reference (e.g. \n
becomes
). Is this a bug or a feature?
I can supply a test case that demonstrates this behaviour, if that helps.
Hey,
I'll edit the docs when I have the time, but I wanted to record this for future reference.
For a heist
template, to render a given template, say, index.tpl
, the corresponding call in handler should be like this:
handleIndex :: Handler App App ()
handleIndex = render "index"
That is, the name should be index
, not index.tpl
This isn't explicitly documented anywhere I looked, and it took me an hour to figure out :)
It needs widening to support the 0.9 API. I'm having build failures because of this.
The move to map-syntax removed noSplices
which is used in the default snap template.
The old definition still works:
noSplices :: Splices s
noSplices = return ()
Is this a definition worth adding back to v1? If so, where should it live?
Somehow we missed that
I'm getting the following build error when performing an LTS Haskell build:
[ 9 of 20] Compiling Heist.Internal.Types ( src/Heist/Internal/Types.hs, dist/build/Heist/Internal/Types.o )
src/Heist/Internal/Types.hs:161:21: error:
• No instance for (Semigroup (Splices (I.Splice m)))
arising from a use of ‘<>’
• In the first argument of ‘SpliceConfig’, namely ‘(a1 <> a2)’
In the expression:
SpliceConfig
(a1 <> a2)
(b1 <> b2)
(c1 <> c2)
(d1 <> d2)
(e1 <> e2)
(\ x -> f1 x && f2 x)
In an equation for ‘<>’:
SpliceConfig a1 b1 c1 d1 e1 f1 <> SpliceConfig a2 b2 c2 d2 e2 f2
= SpliceConfig
(a1 <> a2)
(b1 <> b2)
(c1 <> c2)
(d1 <> d2)
(e1 <> e2)
(\ x -> f1 x && f2 x)
|
161 | SpliceConfig (a1 <> a2) (b1 <> b2) (c1 <> c2)
| ^^^^^^^^
src/Heist/Internal/Types.hs:161:32: error:
• No instance for (Semigroup (Splices (I.Splice IO)))
arising from a use of ‘<>’
• In the second argument of ‘SpliceConfig’, namely ‘(b1 <> b2)’
In the expression:
SpliceConfig
(a1 <> a2)
(b1 <> b2)
(c1 <> c2)
(d1 <> d2)
Namespacing gets ignored for a template introduced with withSplices and codeGen.
{-# LANGUAGE OverloadedStrings #-}
module Bug where
import qualified Data.ByteString as B
import Blaze.ByteString.Builder
import Control.Monad.Trans.Either
import Heist
import Heist.Compiled as C
import qualified Data.Text as T
import Control.Lens
import Heist.Compiled.LowLevel as C
dummy :: Monad m => RuntimeSplice m ()
dummy = return ()
mainSplices :: Monad m => Splices (C.Splice m)
mainSplices = "one" ## (oneRender dummy)
oneRender :: Monad m => RuntimeSplice m () -> C.Splice m
oneRender = const $ do
tpl <- C.withSplices (C.callTemplate "sub") oneSplices dummy
return $ C.yieldRuntime $ C.codeGen tpl
oneSplices :: Monad m => Splices (RuntimeSplice m () -> C.Splice m)
oneSplices = mapV (pureSplice . textSplice) $
"two" ## const "should not be spliced in"
heistConfig = emptyHeistConfig
& hcCompiledSplices .~ mainSplices
& hcTemplateLocations .~ [loadTemplates "."]
main = do
initState <- runEitherT $ initHeist heistConfig
case initState of
Left errs -> print errs
Right heistState -> do
builder <- maybe (error "oops") fst $
C.renderTemplate heistState "main"
toByteStringIO B.putStr builder
main.tpl:
One.
<h:one/>
sub.tpl:
Two.
<two/>
<!-- using <h:two/> results error "./sub.tpl: No splice bound for h:two" -->
The output for this is
One.
Two.
should not be spliced in
Expected output would be
One.
Two.
<two/>
Rendering the following template
<a href="${a}"></a>
produces this output:
<a href="${a}" />
According to the HTML5 spec, this means the same as
<a href="${a}">
This has a different meaning, and will break your HTML.
The reason this happens is that in Heist.Compiled.Internal.compileNode
, a tag is 'self-closed' like this if it contains no children. This should only be done for tags that must be empty in HTML5, like br
and img
. In Text.XmlHtml.HTML.Meta
, there is a set of voidTags
that can be used to check if the tag should be self-closed. However, that module isn't exported (yet), which is why I couldn't easily send a pull request. Should I just expose the module and use that in heist? That's how I fixed it locally.
Fixing to IO was the wrong decision here. First, I don't think most use cases even use IO. And second, there are good reasons to want to initialize Heist in monads other than IO.
This isn't a very substantive change, but it ends up affecting a lot of code because the compiled splice type alias gets an additional type variable. If anyone wants to help out with a pull request here, it would be much appreciated.
nix build
builder for '/nix/store/2y56639fzrr25xfn62a21a46rkyy8znn-heist-1.1.0.1.drv' failed with exit code 1; last 10 log lines:
CallStack (from HasCallStack):
error, called at test/suite/Heist/TestCommon.hs:67:13 in main:Heist.TestCommon
Properties Test Cases Total
Passed 2 15 17
Failed 0 32 32
Total 2 47 49
Test suite testsuite: FAIL
Test suite logged to: dist/test/heist-1.1.0.1-testsuite.log
0 of 1 test suites (0 of 1 test cases) passed.
[0 built (1 failed)]
error: build of '/nix/store/2y56639fzrr25xfn62a21a46rkyy8znn-heist-1.1.0.1.drv' failed
I'm not sure how to get that log out unfortunately.
default.nix file used:
{
nixpkgs ? import <nixpkgs> {}
, sources ? import ./nix/sources.nix
, compiler ? "ghc864" } :
let
niv = import sources.nixpkgs {
overlays = [
(_ : _ : { niv = import sources.niv {}; })
] ;
# config = { allowBroken = true; };
config = { };
};
pkgs = niv.pkgs;
myHaskellPackages = pkgs.haskell.packages.${compiler}.override {
overrides = self: super: rec {
map-syntax = self.callCabal2nix "map-syntax" (builtins.fetchGit {
url = "[email protected]:mightybyte/map-syntax.git";
rev = "e5f9b431525b8670d59c96f477f174cb976e99c6";
})
{};
};
};
in
(myHaskellPackages.callCabal2nix "heist" (./.) {})
With MonadFailDesugaring
as default landing in GHC 8.6, the lack of a MonadFail
instance for HeistT
may become more acute, and will probably cause code breakage. It's easy and I think most sensible to add a simple pass-through instance:
instance MonadFail m => MonadFail (HeistT n m) where fail = lift . fail
However, this would differ from the legacy fail
, which is not defined for HeistT
and thus falls to the default implementation, which is just a regular error. So for pure compatibility that could be done instead, although my feeling is that pass-through is a better design.
The documentation for Heist show a call to emptyHeistState but no such function exists.
I think you meant emptyTemplateState? Which meant that something got renamed. Which is cool, except that right after emptyTemplateState is documentation for defaultHeistState. Seems a bit inconsistent.
AfC
I noticed this while making heist
GHC 8.2-ready; CI currently tests only w/ GHC >= 7.4, so the following failure with GHC 7.0.4 wasn't detected (while testing GHC 7.2.2 is messy due to its incomplete SafeHaskell impl which harms more than it helps):
Configuring library for heist-1.0.1.0..
Preprocessing library for heist-1.0.1.0..
Building library for heist-1.0.1.0..
[ 1 of 20] Compiling Data.HeterogeneousEnvironment ( src/Data/HeterogeneousEnvironment.hs, /tmp/heist-1.0.1.0/dist-newstyle/build/x86_64-linux/ghc-7.0.4/heist-1.0.1.0/build/Data/HeterogeneousEnvironment.o )
[ 2 of 20] Compiling Heist.Internal.Types.HeistState ( src/Heist/Internal/Types/HeistState.hs, /tmp/heist-1.0.1.0/dist-newstyle/build/x86_64-linux/ghc-7.0.4/heist-1.0.1.0/build/Heist/Internal/Types/HeistState.o )
src/Heist/Internal/Types/HeistState.hs:427:35:
Not in scope: `liftM'
src/Heist/Internal/Types/HeistState.hs:429:35:
Not in scope: `liftM'
I think we should adapt the lower bound on base
to reflect the actively CI-tested base
range, (i.e. build-depends: base >= 4.5 ..
)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.