The `jst` package exports a single function `jst(pathname, root, args)`,
which loads a file `pathname` from disk, parses it for a superset of JavaScript
-(ES6) which can contain HTML-like constructs, and then generates equivalent
+(ES7) which can contain HTML-like constructs, and then generates equivalent
plain JavaScript code which in turn, can generate the desired HTML.
The system is inspired by Pug (formerly Jade) templates, but emphasizing the
As well as browser-oriented transformations, other potential transformations
such as TypeScript could be applied to all code rather than just `script` tags.
-The HTML `style` tag is currently not handled specially, thus the content will
-most likely be given as a backquoted (template) string, to support embedded
-newlines. To defeat the HTML escaping, it can be wrapped in `_out(...)`, which
-will be explained further below. In the future, we will switch to a dedicated
-CSS parser, or potentially the `less` or `sass` compiler, for `style` tags.
+The HTML `style` tag is treated specially, because it contains CSS, which we
+handle by switching temporarily to another parser that understands CSS. We use
+a slightly modified version of the `clean-css` package to do this. The CSS is
+automatically minified and then HTML-escaped at the time the template is
+compiled. Note: unlike the JST code, it currently cannot contain substitutions.
### HTML class and id shorthand
`div.'class-1'.class-2 {}`
although we expect that this restriction can be lifted in a future version.
+Also, the `style` parser for CSS code can be confused by tag, `id` or `class`
+names that end with `-style`. So we should be careful of code like this,
+ `div.my-style {...}`
+since the `div.my-` prefix won't be seen until parsing is complete, hence the
+parser will switch to CSS parsing inside the braces. Therefore, quote it like
+ `div.'my-style' {...}`
+although again, we expect that this restriction can be lifted in the future.
+
Another slight limitation of the current parser is that it is more permissive
than normal in parsing regular JavaScript code, for instance commas are not
required between function arguments, because HTML templates are basically
import {lineBreak} from "./whitespace"
import {functionFlags, SCOPE_ARROW, SCOPE_SUPER, SCOPE_DIRECT_SUPER, BIND_OUTSIDE, BIND_VAR} from "./scopeflags"
+// Nick
+import CleanCSS from "@ndcode/clean-css"
+import html_escape from "html-escape"
+let clean_css = new CleanCSS()
+
const pp = Parser.prototype
// Check if property name clashes with already added.
} else if (this.type === tt.braceL) { // Nick
let node = this.startNodeAt(startPos, startLoc)
node.tag = base
- node.body = this.parseBlock(false)
+ if (
+ (
+ base.type === 'Identifier' &&
+ base.name === 'style'
+ ) ||
+ (
+ base.type === 'CallExpression' &&
+ base.callee.type === 'Identifier' &&
+ base.callee.name === 'style'
+ )
+ ) {
+ let render = clean_css.minifyEmbedded(this.input, this.pos)
+ if (render.errors.length)
+ throw render.errors
+ for (let i = 0; i < render.warnings.length; ++i)
+ console.log(`clean-css warning: ${render.warnings[i]}`)
+ node.body = {
+ type: 'BlockStatement',
+ body: [
+ {
+ type: 'ExpressionStatement',
+ expression: {
+ type: 'Literal',
+ value: html_escape(render.styles)
+ }
+ }
+ ]
+ }
+ this.pos = render.embeddedEnd
+ this.next()
+ this.expect(tt.braceR)
+ }
+ else
+ node.body = this.parseBlock(false)
base = this.finishNode(node, "HTMLExpression")
} else {
return base