module.exports = function transform(node, compiler, template) { //Find and handle nested <attrs> elements findNestedAttrs(node, compiler, template); var tag; function convertAttrValue(attr, type, attrDef) { type = type || (attrDef ? attrDef.type : 'string') || 'string'; try { return compiler.convertType(attr.value, type, attrDef ? attrDef.allowExpressions !== false : true); } catch (e) { node.addError('Invalid attribute value of "' + attr.value + '" for attribute "' + attr.name + '": ' + e.message); return attr.value; } } function forEachProp(callback, thisObj) { var foundProps = {}; node.forEachAttributeAnyNS(function (attr) { var attrDef = compiler.taglibs.getAttribute(node, attr); if (!attrDef) { // var isAttrForTaglib = compiler.taglibs.isTaglib(attrUri); //Tag doesn't allow dynamic attributes node.addError('The tag "' + tag.name + '" in taglib "' + tag.taglibId + '" does not support attribute "' + attr + '"'); return; } var type = attrDef.type || 'string'; var value; if (compiler.isExpression(attr.value)) { value = attr.value; } else { if (type === 'path') { var pathVar; if (compiler.hasExpression(attr.value)) { value = convertAttrValue(attr, 'string', attrDef); } else { // Resolve the static string to a full path only once pathVar = template.addStaticVar(attr.value, 'require.resolve(' + compiler.convertType(attr.value, 'string', true) + ')'); value = compiler.makeExpression(pathVar); } } else if (type === 'template') { var templateVar; if (compiler.hasExpression(attr.value)) { value = compiler.makeExpression('__helpers.l(' + convertAttrValue(attr, 'string', attrDef) + ')'); } else { // Resolve the static string to a full path only once templateVar = template.addStaticVar(attr.value, '__helpers.l(require.resolve(' + compiler.convertType(attr.value, 'string', true) + '))'); value = compiler.makeExpression(templateVar); } } else { value = convertAttrValue(attr, type, attrDef); } } var propName; if (attrDef.dynamicAttribute) { propName = attr.qName; } else { if (attrDef.targetProperty) { propName = attrDef.targetProperty; } else if (attrDef.preserveName) { propName = attr.localName; } else { propName = removeDashes(attr.localName); } } foundProps[propName] = true; callback.call(thisObj, propName, value, attrDef); }); tag.forEachAttribute(function (attr) { if (attr.hasOwnProperty('defaultValue') && !foundProps[attr.name]) { callback.call(thisObj, attr.name, template.makeExpression(JSON.stringify(attr.defaultValue)), '', attr); } }); } tag = node.tag || compiler.taglibs.getTag(node); var transformer = new Transformer(template, compiler); node = transformer.transformNode(node); var inputAttr = transformer.inputAttr; if (tag) { if (tag.preserveWhitespace) { node.setPreserveWhitespace(true); } if (tag.renderer || tag.template) { if (tag.renderer) { //Instead of compiling as a static XML element, we'll //make the node render as a tag handler node so that //writes code that invokes the handler TagHandlerNode.convertNode(node, tag); if (inputAttr) { node.setInputExpression(template.makeExpression(inputAttr)); } } else { var templatePath = resolver.deresolve(tag.template, compiler.dirname); // The tag is mapped to a template that will be used to perform // the rendering so convert the node into a "IncludeNode" that can // be used to include the output of rendering a template IncludeNode.convertNode(node, templatePath); } forEachProp(function (name, value, attrDef) { if (attrDef.dynamicAttribute && attrDef.targetProperty) { if (attrDef.removeDashes === true) { name = removeDashes(name); } if (node.addDynamicAttribute) { node.addDynamicAttribute(name, value); node.setDynamicAttributesProperty(attrDef.targetProperty); } else { node.setProperty(name, value); } } else { node.setProperty(name, value); } }); } else if (tag.nodeClass) { var NodeCompilerClass = require(tag.nodeClass); compiler.inheritNode(NodeCompilerClass); extend(node, NodeCompilerClass.prototype); NodeCompilerClass.call(node); node.setNodeClass(NodeCompilerClass); forEachProp(function (name, value) { node.setProperty(name, value); }); } } };
doGenerateCode: function (template) { var rendererPath = raptorModulesResolver.deresolve(this.tag.renderer, template.dirname); var handlerVar = addHandlerVar(template, rendererPath); this.tag.forEachImportedVariable(function (importedVariable) { this.setProperty(importedVariable.targetProperty, template.makeExpression(importedVariable.expression)); }, this); var _this = this; var variableNames = []; _this.tag.forEachVariable(function (nestedVar) { var varName; if (nestedVar.nameFromAttribute) { var possibleNameAttributes = nestedVar.nameFromAttribute.split(/\s+or\s+|\s*,\s*/i); for (var i = 0, len = possibleNameAttributes.length; i < len; i++) { var attrName = possibleNameAttributes[i]; var keep = false; if (attrName.endsWith('|keep')) { keep = true; attrName = attrName.slice(0, 0 - '|keep'.length); possibleNameAttributes[i] = attrName; } varName = this.getAttribute(attrName); if (varName) { if (!keep) { this.removeProperty(attrName); } break; } } if (!varName) { this.addError('Attribute ' + possibleNameAttributes.join(' or ') + ' is required'); varName = '_var'; // Let it continue with errors } } else { varName = nestedVar.name; if (!varName) { this.addError('Variable name is required'); varName = '_var'; // Let it continue with errors } } variableNames.push(varName); }, this); if (_this.preInvokeCode.length) { _this.preInvokeCode.forEach(function (code) { template.indent().code(code).code('\n'); }); } template.contextHelperMethodCall('t', function () { template.code('\n').indent(function () { template.line(handlerVar + ',').indent(); if (_this.inputExpression) { template.code(_this.inputExpression); } else { if (_this.dynamicAttributes) { template.indent(function() { _this.setProperty(_this.dynamicAttributesProperty, template.makeExpression(getPropsStr(_this.dynamicAttributes, template))); }); } template.code(getPropsStr(_this.getProperties(), template)); } if (_this.hasChildren()) { var bodyParams = []; variableNames.forEach(function (varName) { bodyParams.push(varName); }); template.code(',\n').line('function(' + bodyParams.join(',') + ') {').indent(function () { _this.generateCodeForChildren(template); }).indent().code('}'); } }); }); if (_this.postInvokeCode.length) { _this.postInvokeCode.forEach(function (code) { template.indent().code(code).code('\n'); }); } }