odesza
Advanced tools
Comparing version 0.6.0 to 0.7.0
170
index.js
@@ -9,26 +9,13 @@ /** | ||
const fs = require('fs'); | ||
const vm = require('vm'); | ||
const path = require('path'); | ||
const stripComments = require('strip-comments'); | ||
const Template = require('./lib/template'); | ||
var useCache = true; | ||
const odesza = {}; | ||
const blocks = {}; | ||
module.exports = odesza; | ||
const cache = { | ||
templates: {}, | ||
paths: {} | ||
}; | ||
// cache control | ||
var useCache = true; | ||
// matches keyword statements (block, include, extends) | ||
const re = /(block|extends|include) ([\/\.\w]+)/g; | ||
/** | ||
* Renders a template with the given variables. | ||
* Creates and returns a new template given `vars` and `basePath`. | ||
* | ||
* @param {string} template The template to render. | ||
* @param {object} options An object of key-value pairs representing the | ||
* @param {object} vars An object of key-value pairs representing the | ||
* variables to be used in the template. | ||
@@ -40,98 +27,28 @@ * @param {string} [basePath] Optional. The base path to use if extend or | ||
odesza.render = function(template, options, basePath) { | ||
options = options && 'object' == typeof options ? options : {}; | ||
template = stripComments(template); | ||
let s = getStatements(template); | ||
// if an extend statement is found, fill the extended template blocks in | ||
if (s.extends.length) { | ||
// only allow one extend statement | ||
if (s.extends.length > 1) { | ||
throw new Error('An odesza template can only extend one file'); | ||
} | ||
// loop over block statements, putting them into memory | ||
s.block.forEach(block => { | ||
// if the block is in memory, this means there is multiple inheritence, | ||
// i.e. this has already extended | ||
if (blocks[block] != null) return; | ||
// gets the content between the block statements | ||
let start = template.indexOf(`block ${block}`) + `block ${block}`.length; | ||
let end = template.indexOf(`endblock`, start); | ||
if (end == -1) { | ||
throw new Error(`'endblock' statement required after ${block}`); | ||
} | ||
blocks[block] = template.substr(start, end - start).trim(); | ||
}); | ||
let extendPath = `${basePath}${s.extends[0]}`; | ||
template = odesza.renderFile(extendPath, options); | ||
s = getStatements(template); | ||
} else { | ||
s.block.forEach(block => { | ||
if (blocks[block] != null) { | ||
template = template.split(`block ${block}`).join(blocks[block]); | ||
delete blocks[block]; | ||
} else { | ||
// if not in memory, it is a block statement that can be ignored | ||
template = template.split(`block ${block}`).join(''); | ||
} | ||
}); | ||
odesza.render = function(template, vars, basePath) { | ||
if (basePath == null) { | ||
basePath = process.cwd(); | ||
} | ||
var t = new Template(useCache); | ||
return t.render(template, vars, basePath); | ||
}; | ||
// recursively replace each import statement with its rendered template | ||
s.include.forEach(statement => { | ||
let p = `${basePath}${statement}`; | ||
template = template | ||
.split(`include ${statement}`) | ||
.join(odesza.renderFile(p, options)); | ||
}); | ||
return vm.runInNewContext('`' + template + '`', options).trim(); | ||
}; | ||
/** | ||
* Renders a template file. | ||
* Creates and returns a rendered template from a file location. | ||
* | ||
* @param {string} location The location to the template file. | ||
* @param {object} options Options passed in to render the template. | ||
* @param {object} vars variables passed in to render the template. | ||
* @return {string} The rendered template. | ||
*/ | ||
odesza.renderFile = function(location, options) { | ||
var template; | ||
let basePath = location.substr(0, location.lastIndexOf('/') + 1); | ||
location = resolvePath(location); | ||
if (useCache && cache.templates[location] != null) { | ||
template = cache.templates[location]; | ||
} else { | ||
template = fs.readFileSync(location).toString().trim(); | ||
cache.templates[location] = template; | ||
} | ||
return odesza.render(template, options, basePath); | ||
odesza.renderFile = function(location, vars) { | ||
var t = new Template(useCache); | ||
return t.renderFile(location, vars); | ||
}; | ||
/** | ||
* Disables caching. | ||
* Adds support for Express framework. | ||
* | ||
* @public | ||
*/ | ||
odesza.disableCache = function() { | ||
useCache = false; | ||
}; | ||
/** | ||
* Adds support for express. | ||
* | ||
* @public | ||
* @param {string} file | ||
@@ -151,52 +68,9 @@ * @param {object} options | ||
/** | ||
* Returns an object of keyword statements for a given template string. | ||
* Disables template and path caching (all fs lookups). | ||
* | ||
* @private | ||
* @param {string} template The template string to find keywords in. | ||
* @return {object} An object ontaining extends, block, and include statements | ||
* found in the template string. | ||
* @public | ||
*/ | ||
function getStatements(template) { | ||
var s = { | ||
extends: [], | ||
block: [], | ||
include: [] | ||
}; | ||
var m; | ||
while ((m = re.exec(template)) != null) { | ||
s[m[1]].push(m[2]); | ||
} | ||
return s; | ||
} | ||
/** | ||
* Resolves the template file path, throwing an error if anything is wrong | ||
* | ||
* @private | ||
* @param {string} file The relative file to the file. | ||
* @return {string} The resolved path for the file. | ||
*/ | ||
function resolvePath(file) { | ||
if (typeof file != 'string') { | ||
throw new TypeError('invalid file: input must be a string'); | ||
} | ||
if (useCache && cache.paths[file] != null) { | ||
return cache.paths[file]; | ||
} | ||
var resolvedPath = path.resolve(file); | ||
if (!fs.existsSync(resolvedPath)) { | ||
if (fs.existsSync(`${resolvedPath}.ode`)) { | ||
resolvedPath += '.ode'; | ||
} else if (fs.existsSync(`${resolvedPath}.odesza`)) { | ||
resolvedPath += '.odesza'; | ||
} else { | ||
throw new Error(`cannot find file with file: ${file}`); | ||
} | ||
} | ||
cache.paths[file] = resolvedPath; | ||
return resolvedPath; | ||
} | ||
module.exports = odesza; | ||
odesza.disableCache = function() { | ||
useCache = false; | ||
}; |
{ | ||
"name": "odesza", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"description": "Write clean, expressive templates with just HTML and inline JavaScript", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
# Odesza | ||
Odesza is a templating engine that allows you to write clean, expressive templates with inline JavaScript. Some of the features include | ||
Odesza is a templating engine that allows you to write clean, expressive templates with inline JavaScript. Think of it as JS template strings, but for anything. | ||
@@ -10,4 +10,4 @@ - multiple inheritance (extends, includes, block scope) | ||
### Inspiration | ||
I find learning templating languages to be more of a hassle than just writing the HTML. Hence, there is no magic or shorthand code in Odesza templates. Odesza simply provides a structure for you to write complex templating systems without having to learn a new language. Simply put, it offers the flexibility of multiple inheritance and inline programming logic with the familiarity of writing plain HTML and JS. | ||
### Goal | ||
Take inheritance, partials, and inline JS ideas from Jade and strip away the "magic" and shorthand HTML syntax. | ||
@@ -14,0 +14,0 @@ ### Syntax |
20786
29
366