khufu
Version:
A template language for incremental-dom or DSL for javascript views
101 lines (93 loc) • 3.21 kB
JavaScript
import * as T from "babel-types"
import {push_to_body} from './babel-util'
import {parse_tree_error} from './compiler'
import postcss from 'postcss'
function rule(parent, item, cls, opt) {
let [_rule, selectors, properties] = item;
if(opt.additional_class) {
selectors = selectors.map(sel =>
sel.replace(/^([a-zA-Z0-9-]*)/, '$1' + cls))
}
let rule = postcss.rule({'selector': selectors.join(', ')})
for(var line of properties) {
switch(line[0]) {
case 'property': {
let [_property, prop, value] = line;
rule.push(postcss.decl({prop, value}))
break;
}
}
}
parent.push(rule)
}
export function to_postcss(body, opt) {
let root = postcss.root();
let buf = []
let cls = (opt.additional_class || "").replace(/^\s*|\s+/g, '.')
for(var item of body) {
switch(item[0]) {
case 'rule': {
rule(root, item, cls, opt)
break;
}
case 'media': {
let [_media, filter, rules] = item;
let atrule = postcss.rule({selector: '@media ' + filter})
for(var item of rules) {
rule(atrule, item, cls, opt)
}
root.push(atrule)
break;
}
default:
throw parse_tree_error('Unknown element', body)
}
}
return root
}
function scan_for_tags(body, opt) {
for(var item of body) {
switch(item[0]) {
case 'rule': {
let [_rule, selectors, properties] = item;
for(let sel of selectors) {
// add all bare tags
if(/^[a-zA-Z0-9]+$/.exec(sel)) {
opt.always_add_class.add(sel)
}
}
break;
}
}
}
}
export function compile_text(body, opt) {
scan_for_tags(body, opt)
return postcss(opt.postcss || [])
.process(body, {parser: body => to_postcss(body, opt)}).css;
}
export function compile(style, path, opt) {
let [_style, body] = style;
if(!path.scope.getData('khufu:style-imported')) {
path.unshiftContainer("body", T.importDeclaration(
[T.importSpecifier(
T.identifier("add_style"), T.identifier("add_style"))],
T.stringLiteral("khufu-runtime")))
path.scope.setData('khufu:style-imported', true)
}
let data = compile_text(body, opt)
let id = path.scope.generateUidIdentifier('style_remover');
push_to_body(path, T.variableDeclaration('let', [
T.variableDeclarator(id,
T.callExpression(T.identifier('add_style'),
[T.stringLiteral(data)]))
]));
push_to_body(path, T.ifStatement(
T.memberExpression(T.identifier('module'), T.identifier('hot')),
T.blockStatement([T.expressionStatement(
T.callExpression(
T.memberExpression(
T.memberExpression(T.identifier('module'), T.identifier('hot')),
T.identifier('dispose')),
[id]))])))
}