Simple template compilation is working

This commit is contained in:
Patrick Steele-Idem 2014-01-24 14:27:15 -07:00
parent a5ad8e681a
commit 4cf0ae528c
99 changed files with 597 additions and 772 deletions

View File

@ -26,8 +26,8 @@
*
*
*/
var createError = require('raptor-util').createError;
'use strict';
var createError = require('raptor-util').createError;
var strings = require('raptor-strings');
var TypeConverter = require('./TypeConverter');
var regExp = /"(?:[^"]|\\")*"|'(?:[^']|\\')*'|==|===|[;=]/g;

View File

@ -16,12 +16,13 @@
'use strict';
var createError = require('raptor-util').createError;
var forEach = raptor.forEach;
var objects = require('raptor-objects');
var escapeXmlAttr = require('raptor-xml/utils').escapeXmlAttr;
var escapeXmlAttr = require('raptor-xml/util').escapeXmlAttr;
var XML_URI = 'http://www.w3.org/XML/1998/namespace';
var XML_URI_ALT = 'http://www.w3.org/XML/1998/namespace';
var ExpressionParser = require('./ExpressionParser');
var forEachEntry = require('raptor-util').forEachEntry;
function ElementNode(localName, uri, prefix) {
ElementNode.$super.call(this, 'element');
if (!this._elementNode) {
@ -127,7 +128,7 @@ ElementNode.prototype = {
delete this.attributesByNS[uri || ''];
},
isPreserveWhitespace: function () {
var preserveSpace = ElementNode.superclass.isPreserveWhitespace.call(this);
var preserveSpace = ElementNode.$super.prototype.isPreserveWhitespace.call(this);
if (preserveSpace === true) {
return true;
}
@ -217,7 +218,7 @@ ElementNode.prototype = {
template.attr(name, attrParts[0].expression, attrParts[0].escapeXml !== false);
} else {
template.text(' ' + name + '="');
forEach(attrParts, function (part) {
attrParts.forEach(function (part) {
if (part.text) {
template.text(part.escapeXml !== false ? escapeXmlAttr(part.text) : part.text);
} else if (part.expression) {

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
define.Enum('raptor/templating/compiler/EscapeXmlContext', [
module.exports = require('raptor-util').makeEnum([
'Element',
'Attribute'
]);

View File

@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var createError = require('raptor-util').createError;
'use strict';
var createError = require('raptor-util').createError;
var Expression = require('./Expression');
var strings = require('raptor-strings');
var stringify = require('raptor-json/stringify');
@ -29,13 +29,12 @@ var endingTokens = {
};
function createStartRegExpStr(starts) {
var parts = [];
raptor.forEach(starts, function (start) {
starts.forEach(function (start) {
parts.push(regexp.escape('\\\\' + start));
parts.push(regexp.escape('\\' + start));
parts.push(regexp.escape(start));
});
module.exports = parts.join('|');
return;
return parts.join('|');
}
var startRegExpStr = createStartRegExpStr([
'{%',
@ -46,9 +45,9 @@ var startRegExpStr = createStartRegExpStr([
'{?'
]);
function createStartRegExp() {
module.exports = new RegExp(startRegExpStr, 'g');
return;
return new RegExp(startRegExpStr, 'g');
}
function getLine(str, pos) {
var lines = str.split('\n');
var index = 0;
@ -68,8 +67,7 @@ function getLine(str, pos) {
str: line,
pos: pos
};
module.exports = ExpressionParser;
return;
return ExpressionParser;
}
function errorContext(str, pos, length) {
var line = getLine(str, pos);
@ -96,8 +94,7 @@ function errorContext(str, pos, length) {
for (i = 0; i < suffix.length; i++) {
context += ' ';
}
module.exports = context;
return;
return context;
}
function getConditionalExpression(expression) {
var tokensRegExp = /"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\\\\;|\\;|[\{\};]/g;
@ -150,18 +147,14 @@ function getConditionalExpression(expression) {
expressionParts.push(expression);
}
});
module.exports = expressionParts.join('+');
return;
return expressionParts.join('+');
}
if (parts.length === 1) {
module.exports = '(' + parts[0] + ' ? ' + 'null' + ' : \'\')';
return;
return '(' + parts[0] + ' ? ' + 'null' + ' : \'\')';
} else if (parts.length === 2) {
module.exports = '(' + parts[0] + ' ? ' + getExpression(parts[1]) + ' : \'\')';
return;
return '(' + parts[0] + ' ? ' + getExpression(parts[1]) + ' : \'\')';
} else if (parts.length === 3) {
module.exports = '(' + parts[0] + ' ? ' + getExpression(parts[1]) + ' : ' + getExpression(parts[2]) + ')';
return;
return'(' + parts[0] + ' ? ' + getExpression(parts[1]) + ' : ' + getExpression(parts[2]) + ')';
} else {
throw new Error('Invalid simple conditional of "' + expression + '". Simple conditionals should be in the form {?<expression>;<true-template>[;<false-template>]}');
}
@ -191,8 +184,7 @@ function processNestedStrings(expression, foundStrings) {
expression = expression.substring(0, foundString.start) + '(' + parts.join('+') + ')' + expression.substring(foundString.end);
}
}
module.exports = expression;
return;
return expression;
}
var ExpressionParserHelper = function () {
function Class(callback, callbackThisObj) {
@ -244,6 +236,7 @@ var ExpressionParserHelper = function () {
};
return Class;
}();
function ExpressionParser() {
}
/**

View File

@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var createError = require('raptor-util').createError;
'use strict';
var createError = require('raptor-util').createError;
var forEachEntry = require('raptor-util').forEachEntry;
var isArray = Array.isArray;
var isEmpty = require('raptor-objects').isEmpty;
function Node(nodeType) {
@ -245,7 +246,7 @@ Node.prototype = {
if (!childNodes) {
return;
}
raptor.forEach(childNodes, function (childNode) {
childNodes.forEach(function (childNode) {
this.appendChild(childNode);
}, this);
},
@ -335,7 +336,7 @@ Node.prototype = {
return false;
}
if (isArray(node)) {
raptor.forEach(node, function (node) {
node.forEach(function (node) {
this.insertAfter(node, referenceNode);
referenceNode = node;
}, this);

View File

@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var createError = require('raptor-util').createError;
'use strict';
var createError = require('raptor-util').createError;
var sax = require('raptor-xml/sax');
var forEach = raptor.forEach;
var TextNode = require('./TextNode');
var ElementNode = require('./ElementNode');
function ParseTreeBuilder() {
@ -67,7 +66,7 @@ ParseTreeBuilder.prototype = {
var elementNode = new ElementNode(el.getLocalName(), taglibs.resolveURI(el.getNamespaceURI()), el.getPrefix());
elementNode.addNamespaceMappings(el.getNamespaceMappings());
elementNode.pos = parser.getPos();
forEach(el.getAttributes(), function (attr) {
el.getAttributes().forEach(function (attr) {
if (attr.getLocalName() === 'imports' && !attr.getNamespaceURI()) {
importsAttr = attr.getValue();
}
@ -80,7 +79,7 @@ ParseTreeBuilder.prototype = {
imports = taglibs.getImports(importsAttr);
}
}
forEach(el.getAttributes(), function (attr) {
el.getAttributes().forEach(function (attr) {
var attrURI = taglibs.resolveURI(attr.getNamespaceURI());
var attrLocalName = attr.getLocalName();
var attrPrefix = attr.getPrefix();

View File

@ -28,6 +28,7 @@ function Taglib() {
this.functions = [];
this.helperObject = null;
this.patternAttributes = [];
this.importPaths = [];
}
Taglib.prototype = {
@ -268,11 +269,11 @@ Taglib.Transformer = function () {
}
Transformer.prototype = {
getInstance: function () {
if (!this.className) {
if (!this.filename) {
throw createError(new Error('Transformer class not defined for tag transformer (tag=' + this.tag + ')'));
}
if (!this.instance) {
var Clazz = require(this.className);
var Clazz = require(this.filename);
if (Clazz.process) {
return Clazz;
}
@ -282,19 +283,19 @@ Taglib.Transformer = function () {
return this.instance;
},
toString: function () {
return '[Taglib.Transformer: ' + this.className + ']';
return '[Taglib.Transformer: ' + this.filename + ']';
}
};
return Transformer;
}();
Taglib.Function = function () {
function Function() {
function Func() {
this.name = null;
this.functionClass = null;
this.bindToContext = false;
}
Function.prototype = {};
return Function;
Func.prototype = {};
return Func;
}();
Taglib.HelperObject = function () {
function HelperObject() {

View File

@ -16,10 +16,9 @@
/**
* Merges a set of taglibs for ea
*/
'use strict';
var createError = require('raptor-util').createError;
var forEachEntry = require('raptor-util').forEachEntry;
'use strict';
var forEach = raptor.forEach;
var strings = require('raptor-strings');
var ElementNode = require('./ElementNode');
var TextNode = require('./TextNode');
@ -38,26 +37,21 @@ function getImported(lookup, localName, imports) {
name = localName.substring(prefixEnd + 1);
uri = imports._prefixes[prefix];
if (uri) {
function TaglibCollection() {
}
TaglibCollection.prototype = {
return {
uri: uri,
name: name,
prefix: prefix
};
module.exports = TaglibCollection;
return;
}
}
module.exports = null;
return;
return null;
}
function Imports(taglibs, importsStr) {
this._tagImports = {};
this._attrImports = {};
this._prefixes = {};
var parts = strings.trim(importsStr).split(/\s*;\s*/);
forEach(parts, function (part) {
parts.forEach(function (part) {
if (!part) {
//Skip empty strings
return;
@ -83,7 +77,7 @@ function Imports(taglibs, importsStr) {
}
this._prefixes[as] = from;
if (imports) {
forEach(imports.split(/\s*,\s*/), function (importedTagName) {
imports.split(/\s*,\s*/).forEach(function (importedTagName) {
importsLookup[importedTagName] = true;
});
}
@ -243,10 +237,11 @@ TaglibCollection.prototype = {
/*
* Now register all of the text transformers that are part of the provided taglibs
*/
forEach(taglib.textTransformers, function (textTransformer) {
taglib.textTransformers.forEach(function (textTransformer) {
this.textTransformers[textTransformer.className] = textTransformer;
}, this);
forEach(taglib.functions, function (func) {
taglib.functions.forEach(function (func) {
if (!func.name) {
throw createError(new Error('Function name not set.'));
}
@ -310,7 +305,11 @@ TaglibCollection.prototype = {
var handled = {};
var before = {};
function _addTransformers(transformers) {
raptor.forEach(transformers, function (transformer) {
if (!transformers) {
return;
}
transformers.forEach(function (transformer) {
if (!transformer) {
throw createError(new Error('Invalid transformer'));
}
@ -343,7 +342,11 @@ TaglibCollection.prototype = {
}
_handleTransformer(matchingTransformersByName[transformer.after]); //Handle any transformers that this transformer is supposed to run after
}
raptor.forEach(before[transformer.className], _handleTransformer);
if (before[transformer.className]) {
before[transformer.className].forEach(_handleTransformer);
}
//Handle any transformers that are configured to run before this transformer
callback.call(thisObj, transformer);
}

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var createError = require('raptor-util').createError;
'use strict';
var objectMapper = require('raptor-xml/sax/object-mapper');
var createError = require('raptor-util').createError;
var objectMapper = require('raptor-xml/object-mapper');
var regexp = require('raptor-regexp');
var Taglib = require('./Taglib');
var Tag = Taglib.Tag;
@ -24,26 +24,33 @@ var Property = Taglib.Property;
var NestedVariable = Taglib.NestedVariable;
var ImportedVariable = Taglib.ImportedVariable;
var Transformer = Taglib.Transformer;
var Function = Taglib.Function;
var Func = Taglib.Function;
var HelperObject = Taglib.HelperObject;
var nodePath = require('path');
var fs = require('fs');
var STRING = 'string';
var BOOLEAN = 'boolean';
var OBJECT = 'object';
function TaglibXmlLoader(src, resource) {
function TaglibXmlLoader(src, filePath) {
this.src = src;
this.filePath = typeof resource === 'string' ? resource : resource.getURL();
this.resource = resource;
this.filePath = filePath;
}
TaglibXmlLoader.load = function (src, resource) {
var loader = new TaglibXmlLoader(src, resource);
TaglibXmlLoader.load = function (src, filePath) {
var loader = new TaglibXmlLoader(src, filePath);
return loader.load();
};
TaglibXmlLoader.prototype = {
load: function () {
var src = this.src;
var filePath = this.filePath;
var taglibResource = this.resource;
var dirname = nodePath.dirname(filePath);
var tagsById = {};
function resolve(path) {
return nodePath.resolve(dirname, path);
}
function handleTagExtends(subTag) {
var extendsId = subTag['extends'];
if (!extendsId) {
@ -164,11 +171,7 @@ TaglibXmlLoader.prototype = {
_type: STRING,
_targetProp: 'version'
},
'short-name': {
_type: STRING,
_targetProp: 'shortName'
},
'uri': {
'alias': {
_type: STRING,
_set: function (taglib, name, value, context) {
if (!taglib.uri) {
@ -178,7 +181,6 @@ TaglibXmlLoader.prototype = {
}
}
},
'prefix': { _type: STRING },
'tag': {
_type: OBJECT,
_begin: function () {
@ -295,9 +297,10 @@ TaglibXmlLoader.prototype = {
'import-variable': importVariableHandler,
'transformer-class': {
_type: STRING,
_set: function (tag, name, value) {
_set: function (tag, name, path) {
path = resolve(path);
var transformer = new Transformer();
transformer.className = value;
transformer.filename = path;
tag.addTransformer(transformer);
}
},
@ -311,7 +314,10 @@ TaglibXmlLoader.prototype = {
},
'class-name': {
_type: STRING,
_targetProp: 'className'
_set: function (transformer, name, path) {
path = resolve(path);
transformer.filename = path;
}
},
'after': {
_type: STRING,
@ -324,7 +330,7 @@ TaglibXmlLoader.prototype = {
'<properties>': {
_type: OBJECT,
_begin: function (parent) {
return parent.properties = {};
return (parent.properties = {});
},
'<*>': { _type: STRING }
}
@ -340,7 +346,10 @@ TaglibXmlLoader.prototype = {
},
'class-name': {
_type: STRING,
_targetProp: 'className'
_set: function (transformer, name, path) {
path = resolve(path);
transformer.filename = path;
}
}
},
'import-taglib': {
@ -349,27 +358,23 @@ TaglibXmlLoader.prototype = {
return {};
},
_end: function (importedTaglib) {
var path = importedTaglib.path;
var importedXmlSource;
var importedTaglibResource;
if (path.startsWith('/')) {
importedTaglibResource = require('raptor-resources').findResource(path);
} else {
importedTaglibResource = taglibResource.resolve(path);
}
if (!importedTaglibResource.exists()) {
var path = resolve(importedTaglib.path);
taglib.importPaths.push(path);
if (!fs.existsSync(path)) {
throw createError(new Error('Imported taglib with path "' + path + '" not found in taglib at path "' + filePath + '"'));
}
require('raptor-templates/compiler').recordLoadedTaglib(importedTaglibResource);
importedXmlSource = importedTaglibResource.readAsString();
objectMapper.read(importedXmlSource, importedTaglibResource.getURL(), handlers);
var importedXmlSource = fs.readFileSync(path);
require('../work-dir').recordLoadedTaglib(path);
objectMapper.read(importedXmlSource, path, handlers);
},
'path': { _type: STRING }
},
'function': {
_type: OBJECT,
_begin: function () {
return new Function();
return new Func();
},
_end: function (func) {
taglib.addFunction(func);
@ -377,7 +382,10 @@ TaglibXmlLoader.prototype = {
'name': { _type: STRING },
'class': {
_type: STRING,
_targetProp: 'functionClass'
_set: function (func, name, path) {
path = resolve(path);
func.filename = path;
}
},
'bind-to-context': {
_type: BOOLEAN,
@ -394,11 +402,17 @@ TaglibXmlLoader.prototype = {
},
'module-name': {
_type: STRING,
_targetProp: 'moduleName'
_set: function (helperObject, name, path) {
path = resolve(path);
helperObject.moduleName = path;
}
},
'class-name': {
_type: STRING,
_targetProp: 'className'
_set: function (helperObject, name, path) {
path = resolve(path);
helperObject.className = path;
}
}
}
}

View File

@ -13,16 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var createError = require('raptor-util').createError;
'use strict';
var createError = require('raptor-util').createError;
var INDENT = ' ';
var stringify = require('raptor-json/stringify');
var strings = require('raptor-strings');
var StringBuilder = require('raptor-strings/StringBuilder');
var Expression = require('./Expression');
var forEach = raptor.forEach;
var arrayFromArguments = require('raptor-util').arrayFromArguments;
function CodeWriter(indent) {
this._indent = indent != null ? indent : INDENT + INDENT;
this._code = strings.createStringBuilder();
this._code = new StringBuilder();
this.firstStatement = true;
this._bufferedText = null;
this._bufferedContextMethodCalls = null;
@ -43,7 +44,7 @@ CodeWriter.prototype = {
if (!this._bufferedContextMethodCalls) {
this._bufferedContextMethodCalls = [];
}
args = require('raptor-arrays').arrayFromArguments(arguments, 1);
args = arrayFromArguments(arguments, 1);
this._bufferedContextMethodCalls.push([
methodName,
args
@ -117,7 +118,7 @@ CodeWriter.prototype = {
}
this.firstStatement = false;
this._bufferedContextMethodCalls = null;
forEach(_bufferedContextMethodCalls, function (curWrite, i) {
_bufferedContextMethodCalls.forEach(function (curWrite, i) {
var methodName = curWrite[0];
var args = curWrite[1];
if (i === 0) {
@ -278,7 +279,7 @@ TemplateBuilder.prototype = {
}
out.append(indent + 'var ');
var declarations = [];
forEach(vars, function (v, i) {
vars.forEach(function (v, i) {
declarations.push((i !== 0 ? indent + ' ' : '') + v.name + ' = ' + v.expression + (i === vars.length - 1 ? ';\n' : ',\n'));
});
out.append(declarations.join(''));
@ -404,7 +405,7 @@ TemplateBuilder.prototype = {
if (this.hasErrors()) {
return '';
}
var out = strings.createStringBuilder();
var out = new StringBuilder();
var templateName = this.getTemplateName();
if (!templateName) {
this.addError('Template name not defined in template at path "' + this.getFilePath() + '"');
@ -415,21 +416,18 @@ TemplateBuilder.prototype = {
} else {
params = ['context'];
}
out.append('$rset("rhtml", ');
out.append(stringify(templateName));
out.append(', ');
out.append('function(helpers, templateInfo) {\n');
out.append('function create(helpers) {\n');
//Write out the static variables
this.writer.flush();
this._writeVars(this.staticVars, out, INDENT);
out.append('\n' + INDENT + 'return function(data, context) {\n');
out.append('\n' + INDENT + 'return function render(data, context) {\n');
//Write out the render variables
if (this.vars && this.vars.length) {
this._writeVars(this.vars, out, INDENT + INDENT);
out.append('\n');
}
out.append(this.writer.getOutput());
out.append(INDENT + '}\n});');
out.append(INDENT + '};\n}');
return out.toString();
},
setTemplateName: function (templateName) {

View File

@ -13,38 +13,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var createError = require('raptor-util').createError;
'use strict';
var createError = require('raptor-util').createError;
var TemplateBuilder = require('./TemplateBuilder');
var ParseTreeBuilder = require('./ParseTreeBuilder');
var Expression = require('./Expression');
var minifier = require.exists('raptor/js-minifier') ? require('raptor-js-minifier') : null;
var TypeConverter = require('./TypeConverter');
var logger = require('raptor-logging').logger(module);
function TemplateCompiler(taglibs, options) {
this.taglibs = taglibs;
this.options = options || {};
this.workDir = this.options.workDir || require('raptor-templates/compiler').workDir || require('raptor-temp').workDir;
this.errors = [];
}
TemplateCompiler.prototype = {
transformTree: function (rootNode, templateBuilder) {
if (!templateBuilder) {
throw createError(new Error('The templateBuilder argument is required'));
}
var _this = this;
function transformTreeHelper(node) {
try {
this.taglibs.forEachNodeTransformer(node, function (transformer) {
_this.taglibs.forEachNodeTransformer(node, function (transformer) {
if (!node.isTransformerApplied(transformer)) {
//Check to make sure a transformer of a certain type is only applied once to a node
node.setTransformerApplied(transformer);
//Mark the node as have been transformed by the current transformer
this._transformerApplied = true;
_this._transformerApplied = true;
//Set the flag to indicate that a node was transformed
node.compiler = this;
transformer.getInstance().process(node, this, templateBuilder); //Have the transformer process the node (NOTE: Just because a node is being processed by the transformer doesn't mean that it has to modify the parse tree)
node.compiler = _this;
transformer.getInstance().process(node, _this, templateBuilder); //Have the transformer process the node (NOTE: Just because a node is being processed by the transformer doesn't mean that it has to modify the parse tree)
}
}, this);
});
} catch (e) {
throw createError(new Error('Unable to compile template at path "' + templateBuilder.filePath + '. Error: ' + e.message), e);
}
@ -60,8 +62,8 @@ TemplateCompiler.prototype = {
if (!childNode.parentNode) {
return; //The child node might have been removed from the tree
}
transformTreeHelper.call(this, childNode);
}, this);
transformTreeHelper(childNode);
});
}
/*
* The tree is continuously transformed until we go through an entire pass where
@ -71,10 +73,10 @@ TemplateCompiler.prototype = {
do {
this._transformerApplied = false;
//Reset the flag to indicate that no transforms were yet applied to any of the nodes for this pass
transformTreeHelper.call(this, rootNode); //Run the transforms on the tree
transformTreeHelper(rootNode); //Run the transforms on the tree
} while (this._transformerApplied);
},
compile: function (xmlSrc, resource, callback, thisObj) {
compile: function (xmlSrc, filePath, callback, thisObj) {
var _this = this;
var rootNode;
var templateBuilder;
@ -88,24 +90,20 @@ TemplateCompiler.prototype = {
error.errors = _this.getErrors();
throw error;
}
var filePath;
if (require('raptor-resources').isResource(resource)) {
filePath = resource.getURL();
} else if (typeof resource === 'string') {
filePath = resource;
}
try {
/*
* First build the parse tree for the tempate
*/
rootNode = ParseTreeBuilder.parse(xmlSrc, filePath, this.taglibs);
//Build a parse tree from the input XML
templateBuilder = new TemplateBuilder(this, resource, rootNode);
templateBuilder = new TemplateBuilder(this, filePath, rootNode);
//The templateBuilder object is need to manage the compiled JavaScript output
this.transformTree(rootNode, templateBuilder);
} catch (e) {
throw createError(new Error('An error occurred while trying to compile template at path "' + filePath + '". Exception: ' + e), e);
}
try {
/*
* The tree has been transformed and we can now generate
@ -120,43 +118,20 @@ TemplateCompiler.prototype = {
var output = templateBuilder.getOutput();
//Get the compiled output from the template builder
//console.error('COMPILED TEMPLATE (' + filePath + ')\n', '\n' + output, '\n------------------');
if (minifier && this.options.minify === true) {
output = minifier.minify(output);
}
if (callback) {
callback.call(thisObj, {
source: output,
templateName: templateBuilder.getTemplateName()
});
}
var options = this.options;
if (options && options.nameCallback) {
options.nameCallback(templateBuilder.getTemplateName());
}
return output;
},
compileAndLoad: function (xmlSrc, resource) {
var compiledSrc = this.compile(xmlSrc, resource, function (result) {
//Get the compiled output for the template
require('raptor-templates').unload(result.templateName); //Unload any existing template with the same name
});
try {
//console.log('compileAndLoad: ' + (resource ? resource.getURL() : '(no resource') + ': ' + compiledSrc);
this._eval(compiledSrc, resource); //Evaluate the compiled code and register the template
} catch (e) {
var filePath;
if (typeof resource === 'string') {
filePath = resource;
} else if (require('raptor-resources').isResource(resource)) {
filePath = resource.getURL();
}
logger.error('Unable to load compiled template: ' + compiledSrc, e);
throw createError(new Error('Unable to load template at path "' + filePath + '". Exception: ' + e.message), e);
}
},
_eval: function (compiledSrc, resource) {
eval(compiledSrc);
},
isExpression: function (expression) {
return expression instanceof Expression;
},

View File

@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var createError = require('raptor-util').createError;
'use strict';
var escapeXml = require('raptor-xml/utils').escapeXml;
var createError = require('raptor-util').createError;
var escapeXml = require('raptor-xml/util').escapeXml;
var EscapeXmlContext = require('./EscapeXmlContext');
var attrReplace = /[&<>\"\']/g;
var replacements = {
'<': '&lt;',
@ -30,7 +32,7 @@ function escapeXmlAttr(str) {
});
return;
}
var EscapeXmlContext = require('./EscapeXmlContext');
function TextNode(text, escapeXml) {
TextNode.$super.call(this, 'text');
if (text != null && typeof text !== 'string') {

View File

@ -0,0 +1,7 @@
var ExpressionParser = require('./ExpressionParser');
function registerCustomExpressionHandler(name, func) {
ExpressionParser.custom[name] = func;
}
exports.registerCustomExpressionHandler = registerCustomExpressionHandler;

View File

@ -14,10 +14,8 @@
* limitations under the License.
*/
'use strict';
var TaglibCollection = require('./TaglibCollection');
var taglibs = new TaglibCollection();
var extend = require('raptor-util').extend;
var ExpressionParser = require('./ExpressionParser');
var defaultOptions = {
minify: false,
preserveWhitespace: {
@ -34,12 +32,9 @@ var defaultOptions = {
'hr': true
}
};
module.exports = {
extend(exports, {
createCompiler: function (options) {
if (this.discoverTaglibs) {
//Only discover taglibs if that method is implemented
this.discoverTaglibs(); //The discoverTaglibs method is implemented on the server so execute it now
}
var TemplateCompiler = require('./TemplateCompiler');
//Get a reference to the TemplateCompiler class
if (options) {
@ -51,37 +46,28 @@ module.exports = {
} else {
options = defaultOptions; //Otherwise, no options were provided so use the default options
}
var taglibs = require('./taglibs').getTaglibCollection();
return new TemplateCompiler(taglibs, options);
},
compile: function (xmlSource, path, options) {
return this.createCompiler(options).compile(xmlSource, path);
compile: function (src, path, options) {
return this.createCompiler(options).compile(src, path);
},
compileAndLoad: function (xmlSource, path, options) {
this.createCompiler(options).compileAndLoad(xmlSource, path);
},
loadTaglibXml: function (taglibXml, path) {
var TaglibXmlLoader = require('./TaglibXmlLoader');
var taglib = TaglibXmlLoader.load(taglibXml, path);
this.addTaglib(taglib);
return taglib;
},
addTaglib: function (taglib) {
taglibs.add(taglib);
},
addTaglibAlias: function (uri, alias) {
taglibs.addAlias(uri, alias);
},
clearTaglibs: function () {
this.taglibs = taglibs = new TaglibCollection();
},
hasTaglib: function (uri) {
return taglibs.isTaglib(uri);
},
registerCustomExpressionHandler: function (name, func) {
ExpressionParser.custom[name] = func;
},
recordLoadedTaglib: function (taglibResource) {
},
defaultOptions: defaultOptions,
taglibs: taglibs
};
Node: require('./Node'),
ElementNode: require('./ElementNode'),
TextNode: require('./TextNode'),
AttributeSplitter: require('./AttributeSplitter'),
ExpressionParser: require('./ExpressionParser'),
Expression: require('./Expression'),
TypeConverter: require('./TypeConverter'),
defaultOptions: defaultOptions
});
require('raptor-detect/runtime', {
server: function() {
require('./index_server');
}
});

View File

@ -0,0 +1,80 @@
'use strict';
var createError = require('raptor-util').createError;
var compiler = require('./compiler');
var resources = require('raptor-resources');
var packaging = require('raptor-packaging');
var discoveryComplete = false;
var searchPathListenerHandler = null;
var loadedTaglibPaths = {};
require('raptor-util').extend(compiler, {
findAndLoadTaglib: function (uri) {
var pathBuilders = [
function (uri) {
var path = uri;
if (!path.endsWith('.rtld')) {
path += '.rtld';
}
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
},
function (uri) {
var lastSlash = uri.lastIndexOf('/');
var shortName = lastSlash === -1 ? uri : uri.substring(lastSlash + 1);
path = uri + '/' + shortName;
if (!path.endsWith('.rtld')) {
path += '.rtld';
}
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
}
];
for (var i = 0, len = pathBuilders.length; i < len; i++) {
var pathBuilder = pathBuilders[i];
var path = pathBuilder(uri);
var taglibResource = require('raptor-resources').findResource(path);
if (taglibResource && taglibResource.exists()) {
var taglib = require('raptor-templates/compiler').loadTaglib(taglibResource);
this.addTaglibAlias(taglib.uri, uri);
return;
}
}
// Last resort: see if the URI is associated with a module that registers
// the taglibs...
require('raptor-templates/compiler').loadModuleTaglibs(uri);
},
discoverTaglibs: function (force) {
if (discoveryComplete && force !== true) {
return;
}
discoveryComplete = true;
this.clearTaglibs();
loadedTaglibPaths = {};
packaging.forEachTopLevelPackageManifest(this.loadPackageTaglibs, this);
resources.forEach('/rtlds', function (rtldsResource) {
if (rtldsResource.isDirectory()) {
rtldsResource.forEachChild(function (rtldResource) {
if (rtldResource.isFile() && rtldResource.getName().endsWith('.rtld')) {
this.loadTaglib(rtldResource);
}
}, this);
}
}, this);
if (!searchPathListenerHandler) {
searchPathListenerHandler = require('raptor-resources').getSearchPath().subscribe('modified', function () {
discoveryComplete = false;
this.discoverTaglibs(); //If the search path is modified then rediscover the taglibs
}, this);
}
},
loadTaglib: function (taglibResource) {
this.recordLoadedTaglib(taglibResource);
var xml = taglibResource.readAsString();
return this.loadTaglibXml(xml, taglibResource);
}
});

36
compiler/lib/taglibs.js Normal file
View File

@ -0,0 +1,36 @@
var TaglibCollection = require('./TaglibCollection');
var fs = require('fs');
var nodePath = require('path');
exports.taglibs = new TaglibCollection();
function getTaglibCollection() {
return exports.taglibs;
}
function addTaglib(taglib) {
getTaglibCollection().add(taglib);
}
function hasTaglib(uri) {
return getTaglibCollection().isTaglib(uri);
}
function loadTaglibXml(taglibXml, path) {
var TaglibXmlLoader = require('./TaglibXmlLoader');
var taglib = TaglibXmlLoader.load(taglibXml, path);
addTaglib(taglib);
return taglib;
}
function loadTaglibFromFile(path) {
var src = fs.readFileSync(path, {encoding: 'utf8'});
loadTaglibXml(src, path);
}
loadTaglibFromFile(nodePath.join(__dirname, '../../taglibs/core/core.rtld'));
exports.addTaglib = addTaglib;
exports.hasTaglib = hasTaglib;
exports.loadTaglibXml = loadTaglibXml;
exports.getTaglibCollection = getTaglibCollection;

3
compiler/package.json Normal file
View File

@ -0,0 +1,3 @@
{
"main": "lib/index.js"
}

View File

@ -0,0 +1 @@
/Users/psteeleidem/development/github/raptorjs3/raptor-templates/test/test-project/simple.rhtml.actual.js

View File

@ -1,28 +0,0 @@
var createError = require('raptor-util').createError;
'use strict';
var nodeRequire = require;
var target = require('./TemplateCompiler');
var vm = require('vm');
require('raptor-util').extend(target, {
_eval: function (compiledSrc, resource) {
var filePath;
if (resource) {
if (typeof resource === 'string') {
filePath = resource;
} else if (require('raptor-resources').isResource(resource)) {
filePath = resource.isFileResource() ? resource.getFilePath() : resource.getURL();
}
}
try {
if (filePath && require('raptor-files').exists(filePath)) {
//This is a hack, but line numbers for SyntaxErrors are getting lost if we don't use require
delete nodeRequire.cache[filePath];
nodeRequire(filePath);
} else {
vm.runInThisContext(compiledSrc, filePath || null);
}
} catch (e) {
throw createError(new Error('Unable to load compile templated at path "' + filePath + '". Exception: ' + e), e);
}
}
});

View File

@ -1,15 +0,0 @@
'use strict';
var target = require('./TemplateCompiler');
require('raptor-util').extend(target, {
_eval: function (compiledSrc, resource) {
var filePath;
if (resource) {
if (typeof resource === 'string') {
filePath = resource;
} else if (require('raptor-resources').isResource(resource)) {
filePath = resource.getURL();
}
}
__rhinoHelpers.runtime.evaluateString(compiledSrc, filePath || null);
}
});

View File

@ -1,87 +0,0 @@
var createError = require('raptor-util').createError;
'use strict';
var target = require('./TemplateCompiler');
var File = require('raptor-files/File');
var resources = require('raptor-resources');
function optionsKey(options) {
var key = JSON.stringify(options);
var crypto = require('crypto');
var shasum = crypto.createHash('sha1');
shasum.update(key);
var checksum = shasum.digest('hex');
if (checksum.length > 5) {
checksum = checksum.substring(0, 5);
}
require('raptor-util').extend(target, checksum);
return;
}
var logger = require('raptor-logging').logger('raptor/templating/compiler/TemplateCompiler_server');
require('raptor-util').extend(target, {
_getOptionsKey: function () {
if (!this._optionsKey) {
this._optionsKey = optionsKey(this.options);
}
return this._optionsKey;
},
_getWorkFile: function (resource) {
if (!this.workDir || !resource || !resource.isFileResource()) {
return null;
}
var path = typeof resource === 'string' ? resource : resource.getPath();
var workFile = new File(this.workDir, path + '.js');
return workFile;
},
_compileResource: function (path) {
var resource = resources.findResource(path);
if (!resource.exists()) {
throw createError(new Error('Unable to compile template with resource path "' + path + '". Resource not found'));
}
var compiledSource;
var outputPath;
var workFile;
if (this.workDir) {
workFile = this._getWorkFile(resource);
}
if (!workFile || !workFile.exists() || resource.lastModified() > workFile.lastModified()) {
var xmlSource = resource.readAsString();
compiledSource = this.compile(xmlSource, resource);
if (workFile) {
// If there is a work file then write out the compiled source so that we don't have to recompile again until the input resource is modified
workFile.writeAsString(compiledSource);
}
} else {
// The work file exists and it is up-to-date so we can use that to return the compiled source
compiledSource = workFile.readAsString();
}
if (workFile) {
outputPath = workFile.getAbsolutePath();
} else {
outputPath = resource.getURL() + '.js';
}
return {
templateResource: resource,
compiledSource: compiledSource,
outputPath: outputPath,
outputFile: workFile
};
},
compileResource: function (path) {
var compiledInfo = this._compileResource(path);
return compiledInfo.compiledSource;
},
compileAndLoadResource: function (path) {
var compiledInfo = this._compileResource(path);
this._eval(compiledInfo.compiledSource, compiledInfo.outputPath);
var resource = compiledInfo.templateResource;
if (require('raptor-templates/compiler').isWatchingEnabled()) {
resource.watch(function () {
console.log('Template modified at path "' + resource.getURL() + '". Reloading template...');
try {
this.compileAndLoadResource(resource);
} catch (e) {
logger.warn('Unable to re-compile modified template at path "' + resource.getURL() + '". Exception: ' + e, e);
}
}, this);
}
}
});

View File

@ -1,36 +0,0 @@
/*
* Copyright 2011 eBay Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @extension Server
*/
'use strict';
var compiler = require('raptor-templates/compiler');
var discoveryComplete = false;
require('raptor-util').extend(compiler, {
discoverTaglibs: function () {
if (discoveryComplete) {
return;
}
discoveryComplete = true;
var taglibPaths = $rget('rtld');
raptor.forEach(taglibPaths, function (path) {
var resource = require('raptor-resources').findResource(path);
if (resource && resource.exists()) {
this.loadTaglibXml(resource.readAsString(), resource.getPath());
}
}, this);
}
});

View File

@ -1,37 +0,0 @@
/*
* Copyright 2011 eBay Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @extension Rhino
*/
'use strict';
var compiler = require('raptor-templates/compiler');
function convertJavaOptions(javaOptions) {
var options = {};
options.templateName = javaOptions.templateName;
require('raptor-util').extend(compiler, options);
return;
}
require('raptor-util').extend(compiler, {
rhinoCompile: function (src, path, javaOptions) {
return this.compile(src, path, convertJavaOptions(javaOptions));
},
rhinoCompileResource: function (path, javaOptions) {
return this.compileResource(path, convertJavaOptions(javaOptions));
},
rhinoCompileAndLoadResource: function (path, javaOptions) {
return this.compileAndLoadResource(path, convertJavaOptions(javaOptions));
}
});

View File

@ -1,230 +0,0 @@
/*
* Copyright 2011 eBay Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @extension Server
*/
var createError = require('raptor-util').createError;
'use strict';
var compiler = require('raptor-templates/compiler');
var logger = require('raptor-logging').logger('raptor/templating/compiler');
var resources = require('raptor-resources');
var packaging = require('raptor-packaging');
var discoveryComplete = false;
var searchPathListenerHandler = null;
var watchingEnabled = false;
var loadedTaglibPaths = {};
var taglibsLastModified = null;
Object.defineProperty(compiler, 'workDir', {
get: function () {
return this._workDir;
},
set: function (val) {
this.setWorkDir(val);
}
});
require('raptor-util').extend(compiler, {
enableWatching: function () {
watchingEnabled = true;
},
disableWatching: function () {
watchingEnabled = false;
},
isWatchingEnabled: function () {
return watchingEnabled;
},
setWatchingEnabled: function (enabled) {
watchingEnabled = enabled;
},
compileAndLoadResource: function (path, options) {
this.createCompiler(options).compileAndLoadResource(path);
},
compileResource: function (path, options) {
return this.createCompiler(options).compileResource(path);
},
loadModuleTaglibs: function (moduleName) {
var manifest = require('raptor-packaging').getModuleManifest(moduleName);
if (manifest) {
this.loadPackageTaglibs(manifest);
}
},
loadPackageTaglibs: function (manifest) {
var taglibs = manifest.getRaptorProp('taglibs');
if (taglibs) {
raptor.forEach(taglibs, function (rtldPath) {
var key = manifest.getURL() + ':' + rtldPath;
if (!loadedTaglibPaths[key]) {
loadedTaglibPaths[key] = true;
var rtldResource = manifest.resolveResource(rtldPath);
if (!rtldResource || !rtldResource.exists()) {
throw createError(new Error('Raptor TLD "' + rtldPath + '" not found for manifest "' + manifest.getURL() + '"'));
}
this.loadTaglib(rtldResource);
}
}, this);
}
},
findAndLoadTaglib: function (uri) {
var pathBuilders = [
function (uri) {
var path = uri;
if (!path.endsWith('.rtld')) {
path += '.rtld';
}
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
},
function (uri) {
var lastSlash = uri.lastIndexOf('/');
var shortName = lastSlash === -1 ? uri : uri.substring(lastSlash + 1);
path = uri + '/' + shortName;
if (!path.endsWith('.rtld')) {
path += '.rtld';
}
if (!path.startsWith('/')) {
path = '/' + path;
}
return path;
}
];
for (var i = 0, len = pathBuilders.length; i < len; i++) {
var pathBuilder = pathBuilders[i];
var path = pathBuilder(uri);
var taglibResource = require('raptor-resources').findResource(path);
if (taglibResource && taglibResource.exists()) {
var taglib = require('raptor-templates/compiler').loadTaglib(taglibResource);
this.addTaglibAlias(taglib.uri, uri);
return;
}
}
// Last resort: see if the URI is associated with a module that registers
// the taglibs...
require('raptor-templates/compiler').loadModuleTaglibs(uri);
},
discoverTaglibs: function (force) {
if (discoveryComplete && force !== true) {
return;
}
discoveryComplete = true;
this.clearTaglibs();
loadedTaglibPaths = {};
packaging.forEachTopLevelPackageManifest(this.loadPackageTaglibs, this);
resources.forEach('/rtlds', function (rtldsResource) {
if (rtldsResource.isDirectory()) {
rtldsResource.forEachChild(function (rtldResource) {
if (rtldResource.isFile() && rtldResource.getName().endsWith('.rtld')) {
this.loadTaglib(rtldResource);
}
}, this);
}
}, this);
if (!searchPathListenerHandler) {
searchPathListenerHandler = require('raptor-resources').getSearchPath().subscribe('modified', function () {
discoveryComplete = false;
this.discoverTaglibs(); //If the search path is modified then rediscover the taglibs
}, this);
}
},
loadTaglib: function (taglibResource) {
this.recordLoadedTaglib(taglibResource);
var xml = taglibResource.readAsString();
return this.loadTaglibXml(xml, taglibResource);
},
recordLoadedTaglib: function (taglibResource) {
var workDir = this.getWorkDir();
if (workDir) {
var taglibsLastModified = this._readTaglibsLastModified(workDir);
taglibsLastModified.lastModified = Math.max(taglibResource.lastModified(), taglibsLastModified.lastModified || 0);
taglibsLastModified.urls[taglibResource.getURL()] = true;
var newStr = taglibsLastModified.lastModified + '\n' + Object.keys(taglibsLastModified.urls).join('\n');
if (newStr != taglibsLastModified.written) {
taglibsLastModified.written = newStr;
this._taglibsWorkFile.writeAsString(newStr);
}
}
},
_readTaglibsLastModified: function (workDir) {
var taglibsWorkFile = this._taglibsWorkFile;
if (taglibsLastModified == null) {
taglibsLastModified = {
lastModified: null,
urls: {},
written: null
};
if (taglibsWorkFile.exists()) {
try {
taglibsLastModified.str = taglibsWorkFile.readAsString();
var lastModifiedEnd = taglibsLastModified.str.indexOf('\n');
taglibsLastModified.lastModified = parseInt(taglibsLastModified.str.substring(0, lastModifiedEnd), 10);
taglibsLastModified.str.substring(lastModifiedEnd + 1).split('\n').forEach(function (url) {
taglibsLastModified.urls[url] = true;
});
} catch (e) {
logger.warn('Unable to read "' + taglibsWorkFile.getAbsolutePath() + '". Exception: ' + e, e);
}
}
}
return taglibsLastModified;
},
_validateWorkDir: function (workDir) {
if (!workDir) {
return;
}
logger.debug('Validating work directory at path "' + workDir + '"...');
var taglibsLastModified = this._readTaglibsLastModified(workDir);
function isUpToDate() {
var lastModified = taglibsLastModified.lastModified;
if (lastModified == null) {
return true;
}
var files = require('raptor-files');
var urls = Object.keys(taglibsLastModified.urls);
for (var i = 0, len = urls.length; i < len; i++) {
var url = urls[i];
if (url.startsWith('file://')) {
var taglibFile = files.fromFileUrl(url);
if (!taglibFile.exists() || taglibFile.lastModified() > lastModified) {
return false;
}
}
}
return true;
}
if (!isUpToDate()) {
console.log('One ore more taglibs modified. Removing compiled templates work directory at path "' + workDir.getAbsolutePath() + '"...');
workDir.remove();
}
},
setWorkDir: function (workDir) {
if (workDir) {
logger.debug('Setting work directory to "' + workDir + '"...');
var File = require('raptor-files/File');
if (typeof workDir === 'string') {
workDir = new File(workDir);
}
this._workDir = workDir;
this._taglibsWorkFile = new File(this._workDir, 'taglibs.txt');
this._validateWorkDir(workDir);
} else {
this._workDir = null;
this._taglibsWorkFile = null;
}
},
getWorkDir: function () {
return this._workDir;
}
});

View File

@ -1,48 +0,0 @@
/*
* Copyright 2011 eBay Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @extension Rhino
*
*/
'use strict';
var createError = require('raptor-util').createError;
function WrappedWriter(javaWriter) {
this.javaWriter = javaWriter;
this.write = function (o) {
if (o != null) {
this.javaWriter.write(o.toString());
}
};
}
require('raptor-util').extend(require('raptor-templates'), {
rhinoRender: function (templateName, data, context) {
if (data && typeof data === 'string') {
try {
data = eval('(' + data + ')'); //Convert the JSON string to a native JavaScript object
} catch (e) {
throw createError('Invalid JSON data passed to "' + templateName + '". Exception: ' + e, e);
}
}
this.render('' + templateName, data, context);
},
rhinoCreateContext: function (javaWriter) {
var context = this.createContext(new WrappedWriter(javaWriter));
//Wrap the Java writer with a JavaScript object
return context;
}
});

View File

@ -18,6 +18,7 @@
"author": "Patrick Steele-Idem <psteeleidem@ebay.com>",
"maintainers": ["Patrick Steele-Idem <psteeleidem@ebay.com>"],
"dependencies": {
"raptor-detect": "~0.1.0-SNAPSHOT",
"raptor-logging": "~0.1.0-SNAPSHOT",
"raptor-strings": "~0.1.0-SNAPSHOT",
"raptor-regexp" : "~0.1.0-SNAPSHOT",

View File

@ -119,8 +119,8 @@ var helpers = {
}
};
templating = {
templateFunc: function (templateName) {
var templateFunc = loadedTemplates[templateName];
templateFunc: function (templatePath) {
var templateFunc = loadedTemplates[templatePath];
//Look for the template function in the loaded templates lookup
if (!templateFunc) {
//See if the template has already been loaded
@ -129,58 +129,58 @@ templating = {
* then it means that the template has not been fully loaded and initialized.
* Therefore, check if the template has been registerd with the name provided
*/
templateFunc = getRegisteredTemplate(templateName);
templateFunc = getRegisteredTemplate(templatePath);
if (!templateFunc && this.findTemplate) {
this.findTemplate(templateName);
templateFunc = getRegisteredTemplate(templateName);
this.findTemplate(templatePath);
templateFunc = getRegisteredTemplate(templatePath);
}
if (templateFunc) {
var templateInfo = this.getTemplateInfo(templateName);
var templateInfo = this.getTemplateInfo(templatePath);
templateFunc = templateFunc(helpers, templateInfo); //Invoke the factory function to get back the rendering function
}
if (!templateFunc) {
throw createError(new Error('Template not found with name "' + templateName + '"'));
throw createError(new Error('Template not found with name "' + templatePath + '"'));
}
loadedTemplates[templateName] = templateFunc; //Store the template rendering function in the lookup
loadedTemplates[templatePath] = templateFunc; //Store the template rendering function in the lookup
}
return templateFunc;
},
getTemplateInfo: function (templateName) {
return { name: templateName };
getTemplateInfo: function (templatePath) {
return { name: templatePath };
},
render: function (templateName, data, context) {
render: function (templatePath, data, context) {
if (!context) {
throw createError(new Error('Context is required'));
}
var templateFunc = this.templateFunc(templateName);
var templateFunc = this.templateFunc(templatePath);
try {
templateFunc(data || {}, context); //Invoke the template rendering function with the required arguments
} catch (e) {
throw createError(new Error('Unable to render template with name "' + templateName + '". Exception: ' + e), e);
throw createError(new Error('Unable to render template with name "' + templatePath + '". Exception: ' + e), e);
}
},
renderToString: function (templateName, data, context) {
renderToString: function (templatePath, data, context) {
var sb = new StringBuilder();
//Create a StringBuilder object to serve as a buffer for the output
if (context === undefined) {
/*
* If a context object is not provided then we need to create a new context object and use the StringBuilder as the writer
*/
this.render(templateName, data, new Context(sb));
this.render(templatePath, data, new Context(sb));
} else {
var _this = this;
/*
* If a context is provided then we need to temporarily swap out the writer for the StringBuilder
*/
context.swapWriter(sb, function () {
_this.render(templateName, data, context);
_this.render(templatePath, data, context);
}); //Swap in the writer, render the template and then restore the original writer
}
return sb.toString(); //Return the final string associated with the StringBuilder
},
unload: function (templateName) {
delete loadedTemplates[templateName];
$rset('rhtml', templateName, undefined);
unload: function (templatePath) {
delete loadedTemplates[templatePath];
$rset('rhtml', templatePath, undefined);
},
getFunction: _getFunction,
createContext: renderContext.createContext,

View File

@ -23,8 +23,9 @@ var strings = require('raptor-strings');
var resources = require('raptor-resources');
var File = require('raptor-files/File');
var templateInfoByName = {};
var logger = require('raptor-logging').logger('raptor/templating_server');
require('raptor-util').extend(require('raptor-templates'), {
var createError = require('raptor-util').createError;
var logger = require('raptor-logging').logger(module);
require('raptor-util').extend(require('./index'), {
findTemplate: function (name) {
var path = name;
var resource;
@ -86,5 +87,47 @@ require('raptor-util').extend(require('raptor-templates'), {
}, function (e) {
logger.error(e);
});
},
_getWorkFile: function (resource) {
if (!this.workDir || !resource || !resource.isFileResource()) {
return null;
}
var path = typeof resource === 'string' ? resource : resource.getPath();
var workFile = new File(this.workDir, path + '.js');
return workFile;
},
_compileResource: function (path) {
var resource = resources.findResource(path);
if (!resource.exists()) {
throw createError(new Error('Unable to compile template with resource path "' + path + '". Resource not found'));
}
var compiledSource;
var outputPath;
var workFile;
if (this.workDir) {
workFile = this._getWorkFile(resource);
}
if (!workFile || !workFile.exists() || resource.lastModified() > workFile.lastModified()) {
var xmlSource = resource.readAsString();
compiledSource = this.compile(xmlSource, resource);
if (workFile) {
// If there is a work file then write out the compiled source so that we don't have to recompile again until the input resource is modified
workFile.writeAsString(compiledSource);
}
} else {
// The work file exists and it is up-to-date so we can use that to return the compiled source
compiledSource = workFile.readAsString();
}
if (workFile) {
outputPath = workFile.getAbsolutePath();
} else {
outputPath = resource.getURL() + '.js';
}
return {
templateResource: resource,
compiledSource: compiledSource,
outputPath: outputPath,
outputFile: workFile
};
}
});

99
runtime/lib/work-dir.js Normal file
View File

@ -0,0 +1,99 @@
exports.workDir = null;
var logger = require('raptor-logging').logger(module);
var taglibsWorkFile = null;
var taglibsLastModified = null;
function getWorkDir() {
return exports.workDir;
}
function _readTaglibsLastModified(workDir) {
var taglibsWorkFile = taglibsWorkFile;
if (taglibsLastModified == null) {
taglibsLastModified = {
lastModified: null,
urls: {},
written: null
};
if (taglibsWorkFile.exists()) {
try {
taglibsLastModified.str = taglibsWorkFile.readAsString();
var lastModifiedEnd = taglibsLastModified.str.indexOf('\n');
taglibsLastModified.lastModified = parseInt(taglibsLastModified.str.substring(0, lastModifiedEnd), 10);
taglibsLastModified.str.substring(lastModifiedEnd + 1).split('\n').forEach(function (url) {
taglibsLastModified.urls[url] = true;
});
} catch (e) {
logger.warn('Unable to read "' + taglibsWorkFile.getAbsolutePath() + '". Exception: ' + e, e);
}
}
}
return taglibsLastModified;
}
function recordLoadedTaglib(taglibResource) {
var workDir = getWorkDir();
if (workDir) {
var taglibsLastModified = _readTaglibsLastModified(workDir);
taglibsLastModified.lastModified = Math.max(taglibResource.lastModified(), taglibsLastModified.lastModified || 0);
taglibsLastModified.urls[taglibResource.getURL()] = true;
var newStr = taglibsLastModified.lastModified + '\n' + Object.keys(taglibsLastModified.urls).join('\n');
if (newStr != taglibsLastModified.written) {
taglibsLastModified.written = newStr;
taglibsWorkFile.writeAsString(newStr);
}
}
}
function _validateWorkDir(workDir) {
if (!workDir) {
return;
}
logger.debug('Validating work directory at path "' + workDir + '"...');
var taglibsLastModified = _readTaglibsLastModified(workDir);
function isUpToDate() {
var lastModified = taglibsLastModified.lastModified;
if (lastModified == null) {
return true;
}
var files = require('raptor-files');
var urls = Object.keys(taglibsLastModified.urls);
for (var i = 0, len = urls.length; i < len; i++) {
var url = urls[i];
if (url.startsWith('file://')) {
var taglibFile = files.fromFileUrl(url);
if (!taglibFile.exists() || taglibFile.lastModified() > lastModified) {
return false;
}
}
}
return true;
}
if (!isUpToDate()) {
console.log('One ore more taglibs modified. Removing compiled templates work directory at path "' + workDir.getAbsolutePath() + '"...');
workDir.remove();
}
}
function setWorkDir(workDir) {
exports.workDir = _workDir;
if (workDir) {
logger.debug('Setting work directory to "' + workDir + '"...');
var File = require('raptor-files/File');
if (typeof workDir === 'string') {
workDir = new File(workDir);
}
taglibsWorkFile = new File(workDir, 'taglibs.txt');
_validateWorkDir(workDir);
} else {
workDir = null;
taglibsWorkFile = null;
}
}
exports.recordLoadedTaglib = recordLoadedTaglib;
exports.setWorkDir = setWorkDir;

View File

@ -39,5 +39,5 @@ AssignNode.prototype = {
}
}
};
require('raptor-util').inherit(AssignNode, require('../../compiler/Node'));
require('raptor-util').inherit(AssignNode, require('../../compiler').Node);
module.exports = AssignNode;

View File

@ -61,5 +61,5 @@ ChooseNode.prototype = {
}
}
};
require('raptor-util').inherit(ChooseNode, require('../../compiler/Node'));
require('raptor-util').inherit(ChooseNode, require('../../compiler').Node);
module.exports = ChooseNode;

View File

@ -19,6 +19,7 @@ function removeDashes(str) {
return lower.toUpperCase();
});
}
var extend = require('raptor-util').extend;
var coreNS = 'http://raptorjs.org/templates/core';
var WriteNode = require('./WriteNode');
var ForNode = require('./ForNode');
@ -30,15 +31,19 @@ var WhenNode = require('./WhenNode');
var OtherwiseNode = require('./OtherwiseNode');
var TagHandlerNode = require('./TagHandlerNode');
var IncludeNode = require('./IncludeNode');
var Expression = require('../../compiler/Expression');
var AttributeSplitter = require('../../compiler/AttributeSplitter');
var TypeConverter = require('../../compiler/TypeConverter');
var Expression = require('../../compiler').Expression;
var AttributeSplitter = require('../../compiler').AttributeSplitter;
var TypeConverter = require('../../compiler').TypeConverter;
function getPropValue(value, type, allowExpressions) {
module.exports = TypeConverter.convert(value, type, allowExpressions);
return;
return TypeConverter.convert(value, type, allowExpressions);
}
function CoreTagTransformer() {
}
CoreTagTransformer.id = 'core/CoreTagTransformer';
CoreTagTransformer.prototype = {
process: function (node, compiler, template) {
//Find and handle nested <c:attrs> elements
@ -102,7 +107,8 @@ CoreTagTransformer.prototype = {
propName = attr.localName;
}
callback.call(thisObj, attrUri, propName, value, prefix, attrDef);
}, this);
});
tag.forEachStaticProperty(function (staticProp) {
var value = getPropValue(staticProp.value, staticProp.type, false);
callback.call(thisObj, '', staticProp.name, value, '', staticProp);

View File

@ -14,8 +14,8 @@
* limitations under the License.
*/
'use strict';
var ExpressionParser = require('../../compiler/ExpressionParser');
var TextNode = require('../../compiler/TextNode');
var ExpressionParser = require('../../compiler').ExpressionParser;
var TextNode = require('../../compiler').TextNode;
var WriteNode = require('./WriteNode');
var ScriptletNode = require('./ScriptletNode');
function CoreTextTransformer() {

View File

@ -55,5 +55,5 @@ DefNode.prototype = {
}, this).line('}');
}
};
require('raptor-util').inherit(DefNode, require('../../compiler/Node'));
require('raptor-util').inherit(DefNode, require('../../compiler').Node);
module.exports = DefNode;

View File

@ -32,5 +32,5 @@ ElseIfNode.prototype = {
}, this).line('}');
}
};
require('raptor-util').inherit(ElseIfNode, require('../../compiler/ElementNode'));
require('raptor-util').inherit(ElseIfNode, require('../../compiler').ElementNode);
module.exports = ElseIfNode;

View File

@ -30,5 +30,5 @@ ElseNode.prototype = {
}, this).line('}');
}
};
require('raptor-util').inherit(ElseNode, require('../../compiler/ElementNode'));
require('raptor-util').inherit(ElseNode, require('../../compiler').ElementNode);
module.exports = ElseNode;

View File

@ -20,28 +20,21 @@ var stringify = require('raptor-json/stringify').stringify;
function parseForEach(value) {
var match = value.match(forEachRegEx);
if (match) {
function ForNode() {
}
ForNode.prototype = {
return {
'var': match[1],
'in': match[2]
};
module.exports = ForNode;
return;
} else {
match = value.match(forEachPropRegEx);
if (!match) {
throw new Error('Invalid each attribute of "' + value + '"');
}
function ForNode() {
}
ForNode.prototype = {
return {
'nameVar': match[1],
'valueVar': match[2],
'in': match[3]
};
module.exports = ForNode;
return;
}
}
function ForNode(props) {
@ -146,5 +139,5 @@ ForNode.prototype = {
}
}
};
require('raptor-util').inherit(ForNode, require('../../compiler/Node'));
require('raptor-util').inherit(ForNode, require('../../compiler').Node);
module.exports = ForNode;

View File

@ -31,5 +31,5 @@ IfNode.prototype = {
}, this).line('}');
}
};
require('raptor-util').inherit(IfNode, require('../../compiler/Node'));
require('raptor-util').inherit(IfNode, require('../../compiler').Node);
module.exports = IfNode;

View File

@ -70,5 +70,5 @@ IncludeNode.prototype = {
}
}
};
require('raptor-util').inherit(IncludeNode, require('../../compiler/Node'));
require('raptor-util').inherit(IncludeNode, require('../../compiler').Node);
module.exports = IncludeNode;

View File

@ -94,5 +94,5 @@ InvokeNode.prototype = {
}
}
};
require('raptor-util').inherit(InvokeNode, require('../../compiler/Node'));
require('raptor-util').inherit(InvokeNode, require('../../compiler').Node);
module.exports = InvokeNode;

View File

@ -30,5 +30,5 @@ OtherwiseNode.prototype = {
return '<c:otherwise>';
}
};
require('raptor-util').inherit(OtherwiseNode, require('../../compiler/Node'));
require('raptor-util').inherit(OtherwiseNode, require('../../compiler').Node);
module.exports = OtherwiseNode;

View File

@ -28,5 +28,5 @@ ScriptletNode.prototype = {
return '{%' + this.code + '%}';
}
};
require('raptor-util').inherit(ScriptletNode, require('../../compiler/Node'));
require('raptor-util').inherit(ScriptletNode, require('../../compiler').Node);
module.exports = ScriptletNode;

View File

@ -15,9 +15,10 @@
*/
'use strict';
var objects = require('raptor-objects');
var forEach = raptor.forEach;
var extend = require('raptor-util').extend;
var forEachEntry = require('raptor-util').forEachEntry;
var stringify = require('raptor-json/stringify');
var Expression = require('../../compiler/Expression');
var Expression = require('../../compiler').Expression;
function addHandlerVar(template, handlerClass) {
var handlerVars = template._handlerVars || (template._handlerVars = {});
var handlerVar = handlerVars[handlerClass];
@ -144,7 +145,7 @@ TagHandlerNode.prototype = {
}
if (_this.hasChildren()) {
var bodyParams = [];
forEach(variableNames, function (varName) {
variableNames.forEach(function (varName) {
bodyParams.push(varName);
});
template.code(',\n').line('function(' + bodyParams.join(',') + ') {').indent(function () {
@ -183,5 +184,5 @@ TagHandlerNode.prototype = {
}
}
};
require('raptor-util').inherit(TagHandlerNode, require('../../compiler/Node'));
require('raptor-util').inherit(TagHandlerNode, require('../../compiler').Node);
module.exports = TagHandlerNode;

View File

@ -14,7 +14,6 @@
* limitations under the License.
*/
'use strict';
var forEach = raptor.forEach;
function TemplateNode(props) {
TemplateNode.$super.call(this);
if (props) {
@ -23,11 +22,10 @@ function TemplateNode(props) {
}
TemplateNode.prototype = {
doGenerateCode: function (template) {
var name = this.getProperty('name');
var params = this.getProperty('params');
if (params) {
params = params.split(/(?:\s*,\s*)|(?:\s+)/g);
forEach(params, function (param) {
params.forEach(function (param) {
param = param.trim();
if (param.length) {
template.addVar(param, 'data.' + param);
@ -41,7 +39,7 @@ TemplateNode.prototype = {
uri = this.uri;
}
if (name === 'functions' || name === 'importFunctions' || name === 'importHelperFunctions') {
forEach(value.split(/\s*[,;]\s*/g), function (funcName) {
value.split(/\s*[,;]\s*/g).forEach(function (funcName) {
var func = template.compiler.taglibs.getFunction(uri, funcName);
if (!func) {
this.addError('Function with name "' + funcName + '" not found in taglib "' + uri + '"');
@ -67,13 +65,9 @@ TemplateNode.prototype = {
}
}
}, this);
if (name) {
template.setTemplateName(name);
} else if (!template.getTemplateName()) {
this.addError('The "name" attribute is required for the ' + this.toString() + ' tag or it must be passed in as a compiler option.');
}
this.generateCodeForChildren(template);
}
};
require('raptor-util').inherit(TemplateNode, require('../../compiler/Node'));
require('raptor-util').inherit(TemplateNode, require('../../compiler').Node);
module.exports = TemplateNode;

View File

@ -36,5 +36,5 @@ VarNode.prototype = {
}
}
};
require('raptor-util').inherit(VarNode, require('../../compiler/Node'));
require('raptor-util').inherit(VarNode, require('../../compiler').Node);
module.exports = VarNode;

View File

@ -37,5 +37,5 @@ WhenNode.prototype = {
}, this).line('}');
}
};
require('raptor-util').inherit(WhenNode, require('../../compiler/Node'));
require('raptor-util').inherit(WhenNode, require('../../compiler').Node);
module.exports = WhenNode;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
var AttributeSplitter = require('../../compiler/AttributeSplitter');
var AttributeSplitter = require('../../compiler').AttributeSplitter;
var varNameRegExp = /^[A-Za-z_][A-Za-z0-9_]*$/;
function WithNode(props) {
WithNode.$super.call(this);
@ -48,5 +48,5 @@ WithNode.prototype = {
}, this).line('}());');
}
};
require('raptor-util').inherit(WithNode, require('../../compiler/Node'));
require('raptor-util').inherit(WithNode, require('../../compiler').Node);
module.exports = WithNode;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
var EscapeXmlContext = require('../../compiler/EscapeXmlContext');
var EscapeXmlContext = require('../../compiler/lib/EscapeXmlContext');
function WriteNode(props) {
WriteNode.$super.call(this, 'write');
if (props) {
@ -48,5 +48,5 @@ WriteNode.prototype = {
return '<c:write expression="' + this.getExpression() + '">';
}
};
require('raptor-util').inherit(WriteNode, require('../../compiler/Node'));
require('raptor-util').inherit(WriteNode, require('../../compiler').Node);
module.exports = WriteNode;

View File

@ -3,9 +3,8 @@
<tlib-version>1.0</tlib-version>
<uri>http://raptorjs.org/templates/core</uri>
<short-name>core</short-name>
<prefix>c</prefix>
<alias>core</alias>
<alias>c</alias>
<tag id="template">
@ -44,7 +43,7 @@
<allow-expressions>false</allow-expressions>
</attribute>
<node-class>raptor/templating/taglibs/core/TemplateNode</node-class>
<node-class>./TemplateNode</node-class>
</tag>
<tag extends="template">
@ -157,7 +156,7 @@
<!-- Compiler that applies to all tags as well -->
<transformer>
<class-name>raptor/templating/taglibs/core/CoreTagTransformer</class-name>
<class-name>./CoreTagTransformer</class-name>
</transformer>
</tag>
@ -167,7 +166,7 @@
<name>for</name>
<node-class>raptor/templating/taglibs/core/ForNode</node-class>
<node-class>./ForNode</node-class>
<attribute>
<name>each</name>
@ -208,7 +207,7 @@
<name>write</name>
<node-class>raptor/templating/taglibs/core/WriteNode</node-class>
<node-class>./WriteNode</node-class>
<attribute>
<name>value</name>
@ -235,7 +234,7 @@
<name>if</name>
<node-class>raptor/templating/taglibs/core/IfNode</node-class>
<node-class>./IfNode</node-class>
<attribute>
<name>test</name>
@ -246,11 +245,11 @@
<tag>
<name>else</name>
<node-class>raptor/templating/taglibs/core/ElseNode</node-class>
<node-class>./ElseNode</node-class>
<transformer>
<class-name>raptor/templating/taglibs/core/ElseTagTransformer</class-name>
<after>raptor/templating/taglibs/core/CoreTagTransformer</after>
<class-name>./ElseTagTransformer</class-name>
<after>core/CoreTagTransformer</after>
<properties>
<type>else</type>
</properties>
@ -261,11 +260,11 @@
<name>else-if</name>
<attribute name="test" type="expression"/>
<node-class>raptor/templating/taglibs/core/ElseIfNode</node-class>
<node-class>./ElseIfNode</node-class>
<transformer>
<class-name>raptor/templating/taglibs/core/ElseTagTransformer</class-name>
<after>raptor/templating/taglibs/core/CoreTagTransformer</after>
<class-name>./ElseTagTransformer</class-name>
<after>core/CoreTagTransformer</after>
<properties>
<type>else-if</type>
</properties>
@ -276,7 +275,7 @@
<name>invoke</name>
<node-class>raptor/templating/taglibs/core/InvokeNode</node-class>
<node-class>./InvokeNode</node-class>
<attribute>
<name>function</name>
@ -297,7 +296,7 @@
<name>choose</name>
<node-class>raptor/templating/taglibs/core/ChooseNode</node-class>
<node-class>./ChooseNode</node-class>
</tag>
@ -305,7 +304,7 @@
<name>when</name>
<node-class>raptor/templating/taglibs/core/WhenNode</node-class>
<node-class>./WhenNode</node-class>
<attribute>
<name>test</name>
@ -318,7 +317,7 @@
<name>otherwise</name>
<node-class>raptor/templating/taglibs/core/OtherwiseNode</node-class>
<node-class>./OtherwiseNode</node-class>
</tag>
@ -326,7 +325,7 @@
<name>def</name>
<node-class>raptor/templating/taglibs/core/DefNode</node-class>
<node-class>./DefNode</node-class>
<attribute>
<name>function</name>
@ -346,7 +345,7 @@
<name>with</name>
<node-class>raptor/templating/taglibs/core/WithNode</node-class>
<node-class>./WithNode</node-class>
<attribute>
<name>vars</name>
@ -360,7 +359,7 @@
<name>include</name>
<node-class>raptor/templating/taglibs/core/IncludeNode</node-class>
<node-class>./IncludeNode</node-class>
<attribute>
<name>template</name>
@ -422,7 +421,7 @@
<name>var</name>
<node-class>raptor/templating/taglibs/core/VarNode</node-class>
<node-class>./VarNode</node-class>
<attribute>
<name>name</name>
@ -455,7 +454,7 @@
<name>assign</name>
<node-class>raptor/templating/taglibs/core/AssignNode</node-class>
<node-class>./AssignNode</node-class>
<attribute>
<name>var</name>
@ -470,7 +469,7 @@
</tag>
<text-transformer>
<class-name>raptor/templating/taglibs/core/CoreTextTransformer</class-name>
<class-name>./CoreTextTransformer</class-name>
</text-transformer>
</raptor-taglib>

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
'use strict';
var ExpressionParser = require('../../compiler/ExpressionParser');
var ExpressionParser = require('../../compiler').ExpressionParser;
function DocTypeNode(props) {
DocTypeNode.$super.call(this);
if (props) {
@ -39,5 +39,5 @@ DocTypeNode.prototype = {
template.text('>');
}
};
require('raptor-util').inherit(DocTypeNode, require('../../compiler/ElementNode'));
require('raptor-util').inherit(DocTypeNode, require('../../compiler').ElementNode);
module.exports = DocTypeNode;

View File

@ -36,14 +36,14 @@ HtmlTagTransformer.prototype = {
if (compiler.options.xhtml !== true && startTagOnly[lookupKey] === true) {
node.setStartTagOnly(true);
}
if (node.getQName() === 'html' && node.hasAttributeNS('http://raptorjs.org/templates/html', 'doctype')) {
var doctype = node.getAttributeNS('http://raptorjs.org/templates/html', 'doctype');
if (node.getQName() === 'html' && node.hasAttributeNS('raptor-templates/html', 'doctype')) {
var doctype = node.getAttributeNS('raptor-templates/html', 'doctype');
var docTypeNode = new DocTypeNode({
value: doctype,
pos: node.getPosition()
});
node.parentNode.insertBefore(docTypeNode, node);
node.removeAttributeNS('http://raptorjs.org/templates/html', 'doctype');
node.removeAttributeNS('raptor-templates/templates/html', 'doctype');
}
}
}

View File

@ -19,7 +19,7 @@ var widgetsNS = 'http://raptorjs.org/templates/widgets';
var strings = require('raptor-strings');
var objects = require('raptor-objects');
var stringify = require('raptor-json/stringify');
var AttributeSplitter = require('../../compiler/AttributeSplitter');
var AttributeSplitter = require('../../compiler').AttributeSplitter;
function WidgetsTagTransformer() {
}
WidgetsTagTransformer.prototype = {

50
test/compiler-tests.js Normal file
View File

@ -0,0 +1,50 @@
'use strict';
var chai = require('chai');
chai.Assertion.includeStack = true;
require('chai').should();
var expect = require('chai').expect;
var nodePath = require('path');
var fs = require('fs');
var logger = require('raptor-logging').logger(module);
function testCompiler(path) {
var inputPath = nodePath.join(__dirname, path);
var expectedPath = nodePath.join(__dirname, path + '.expected.js');
var actualPath = nodePath.join(__dirname, path + '.actual.js');
var compiler = require('../compiler').createCompiler();
var src = fs.readFileSync(inputPath, {encoding: 'utf8'});
var expected = fs.readFileSync(expectedPath, {encoding: 'utf8'});
var output = compiler.compile(src, path);
fs.writeFileSync(actualPath, output, {encoding: 'utf8'});
if (output !== expected) {
throw new Error('Unexpected output for "' + inputPath + '":\nEXPECTED (' + expectedPath + '):\n---------\n' + expected +
'\n---------\nACTUAL (' + actualPath + '):\n---------\n' + output + '\n---------');
}
}
describe('raptor-templates/compiler' , function() {
beforeEach(function(done) {
for (var k in require.cache) {
if (require.cache.hasOwnProperty(k)) {
delete require.cache[k];
}
}
require('raptor-logging').configureLoggers({
'raptor-templates': 'INFO'
});
done();
});
it('should compile a simple template', function(done) {
testCompiler('test-project/simple.rhtml');
});
});

View File

@ -6,6 +6,7 @@ var expect = require('chai').expect;
var path = require('path');
describe('raptor-templates' , function() {
beforeEach(function(done) {

View File

@ -0,0 +1,3 @@
<c:template xmlns:c="core">
Hello John
</c:template>

View File

@ -0,0 +1,8 @@
function create(helpers) {
var empty = helpers.e,
notEmpty = helpers.ne;
return function render(data, context) {
context.w('Hello John');
};
}

View File

@ -0,0 +1,8 @@
function create(helpers) {
var empty = helpers.e,
notEmpty = helpers.ne;
return function render(data, context) {
context.w('Hello John');
};
}