UNPKG

omljs

Version:

Template engine built on top of the Oli language

399 lines 9.68 kB
var fs, oli, tags, ht, ref$, isObject, isArray, isString, isUndef, isArrayStrings, extend, clone, has, cwd, exports, Engine, mixinNameRegex, mixinCallRegex, fileExt, getMixinName, getMixinCall, getMixinArgs, isValid, isSelfClosed, normalize, isDoctype, isMixinNode, isMixinDefinition, isMixinCall; fs = require('fs'); oli = require('oli'); tags = require('./tags'); ht = require('htgen'); ref$ = require('./helpers'), isObject = ref$.isObject, isArray = ref$.isArray, isString = ref$.isString, isUndef = ref$.isUndef, isArrayStrings = ref$.isArrayStrings, extend = ref$.extend, clone = ref$.clone, has = ref$.has, cwd = ref$.cwd; exports = module.exports = Engine = (function(){ Engine.displayName = 'Engine'; var prototype = Engine.prototype, constructor = Engine; Engine.render = function(code, options){ return new Engine(oli.parse(String(code), options), options).compile(); }; Engine.options = { basePath: cwd(), pretty: false, indent: 2 }; function Engine(data, options){ this.data = data; this.mixins = {}; this.buf = []; this.result = null; this.setOptions( options); } prototype.setOptions = function(it){ return this.options = extend(clone( Engine.options), it); }; prototype.compile = function(data){ data == null && (data = this.data); if (isObject( data)) { return this.compileObject( data); } else if (isArray( data)) { return this.compileArray( data); } else { return this.compileRaw( data); } }; prototype.compileObject = function(it){ var this$ = this; this.buf = this.processMixins( this.visitor( it)).filter(isValid).map(function(it){ return this$.processNode( it); }); return this.buf.join( this.separator()); }; prototype.compileArray = function(data){ var buf, iterate, this$ = this; buf = []; (iterate = function(){ var i$, ref$, len$, index, item, results$ = []; for (i$ = 0, len$ = (ref$ = data).length; i$ < len$; ++i$) { index = i$; item = ref$[i$]; if (item) { if (isArray( item)) { if (item = iterate( item)) { results$.push(buf.push( item)); } } else { if (item = this$.compile( item)) { results$.push(buf.push( item)); } } } } return results$; })(); return this.processMixins( buf).join(this.separator()); }; prototype.compileRaw = function(it){ if (isString( it)) { if (isDoctype( it)) { return ht( it).render(this.options); } else if (isSelfClosed( it)) { return ht( "!" + it).render(this.options); } else if (it.charAt(0) === '!') { return ht( it).render(this.options); } else { return it; } } else { return it; } }; prototype.visitor = function(node){ var buf, name, child, own$ = {}.hasOwnProperty; buf = []; for (name in node) if (own$.call(node, name)) { child = node[name]; if (child !== undefined) { name = normalize( name); if ((name === 'include' || name === 'require') && isString( child)) { buf.push( Engine.render(this.readFile( child), this.options)); } else if (isArray( child)) { buf = buf.concat( this.processArray(name, child)); } else if (isMixinDefinition( name)) { if (!has(child, '$$attributes')) { child = { $$attributes: null, $$body: child }; } child.$$body = this.visitMixin( child.$$body); this.registerMixin(name, child); } else { buf.push( this.process(name, child)); } } } return buf; }; prototype.visitMixin = function(it){ var buf, name, node, i$, len$, item, own$ = {}.hasOwnProperty; buf = []; if (isObject( it)) { for (name in it) if (own$.call(it, name)) { node = it[name]; buf.push( this.process(name, node)); } } else if (isArray( it)) { for (i$ = 0, len$ = it.length; i$ < len$; ++i$) { item = it[i$]; buf.push( this.visitor( item)); } } else { buf.push( it); } return buf.join( this.separator()); }; prototype.process = function(name, node){ var attrs; if (node === null) { name = "!" + name; } else if (has(node, '$$attributes')) { attrs = node.$$attributes; node = node.$$body; if (isArray( node)) { node = node.map(function(it){ return this.visitor( it); }); } else if (isObject( node)) { node = this.visitor( node); } } else if (isObject( node)) { node = this.visitor( node); } if (isSelfClosed( name)) { name = "!" + name; } return ht(name, attrs, node); }; prototype.processNode = function(it){ if (isObject( it)) { if (it.mixin) { if (isArray( it.body)) { return it.body.join( this.separator()); } else { return it.body; } } else { return it.render( this.options); } } else { return it; } }; prototype.processArray = function(name, node){ var buf, i$, len$, item; buf = []; if (isArrayStrings( node)) { buf.push( ht.apply(null, [name, node.join(' ')])); } else { for (i$ = 0, len$ = node.length; i$ < len$; ++i$) { item = node[i$]; if (isObject( item)) { if (item.$$name && item.$$attributes && isUndef( item.$$body)) { buf.push( this.process(item.$$name, item)); } else { buf.push( ht(name, this.visitor( item))); } } else { buf.push( ht(name, item)); } } } return buf; }; prototype.processMixins = function(it){ var i$, len$, index, child, name, mixin, callArgs; if (!isArray( it)) { return it; } for (i$ = 0, len$ = it.length; i$ < len$; ++i$) { index = i$; child = it[i$]; if (name = isMixinNode( child)) { if (!(mixin = this.mixins[name])) { throw new Error("Missing required mixin: " + name); } if (child.attributes) { callArgs = Object.keys( child.attributes); } it[index] = this.mixinArguments(mixin, callArgs); } else if (isObject( child) && child.childNodes) { it[index]['childNodes'] = this.processMixins( child.childNodes); } } return it; }; prototype.mixinArguments = function(mixin, callArgs){ var body, args, defValue, i$, len$, aindex, arg, key; callArgs == null && (callArgs = []); body = mixin.body, args = mixin.args; if (!args) { return body; } defValue = ''; for (i$ = 0, len$ = args.length; i$ < len$; ++i$) { aindex = i$; arg = args[i$]; if (isObject( arg)) { key = Object.keys( arg)[0]; defValue = arg[key] || defValue; arg = key; } body = body.replace("$" + arg, callArgs[aindex] || defValue); } return body; }; prototype.registerMixin = function(name, node){ var ref$; name = getMixinName( name); if (!name) { throw new SyntaxError('Missing mixin name identifier'); } return ref$ = this.mixins, ref$[name] = { args: getMixinArgs( node), body: node.$$body }, ref$; }; prototype.separator = function(){ if (this.options.pretty) { return '\n'; } else { return ''; } }; prototype.readFile = function(it){ it = fileExt( it); if (it.charAt(0) !== '/') { it = this.options.basePath + "/" + it; } return fs.readFileSync( it).toString(); }; return Engine; }()); mixinNameRegex = /^mixin ([a-z0-9\_\-\.]+)[\s+]?\(?/i; mixinCallRegex = /^\+[\s+]?([a-z0-9\_\-\.]+)[\s+]?\(?/i; fileExt = function(it){ if (!/\.([a-z\-\_0-9]){0,10}$/i.test(it)) { return it += '.oli'; } else { return it; } }; getMixinName = function(it){ var name; if (name = it.match(mixinNameRegex)) { return name[1]; } }; getMixinCall = function(it){ var name; if (name = it.match(mixinCallRegex)) { return name[1]; } }; getMixinArgs = function(it){ var args, attrs; args = null; if (isObject( it) && isObject( attrs = it.$$attributes)) { args = Object.keys( attrs).map(function(it){ var ref$; if (isUndef( attrs[it])) { return it; } else { return ref$ = {}, ref$[it] = attrs[it], ref$; } }); } return args; }; isValid = function(it){ return isObject( it) || (isString( it) && it.length); }; isSelfClosed = function(it){ return tags.indexOf( it) !== -1; }; normalize = function(it){ return it.replace('@', '#'); }; isDoctype = function(it){ return /^doctype/i.test(it); }; isMixinNode = function(it){ if (isObject( it) && isMixinCall( it.tag)) { return getMixinCall( it.tag); } else if (isMixinCall( it)) { return getMixinCall( it); } else { return false; } }; isMixinDefinition = function(it){ return /^mixin/i.test(it); }; isMixinCall = function(it){ return /^\+/i.test(it); };