diff --git a/README.md b/README.md index 046468474..68bfe20af 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,10 @@ Raptor Templates is an extensible, streaming, asynchronous, [high performance](h + **Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* +- [Design Philosophy](#design-philosophy) - [Sample](#sample) - [Installation](#installation) - [Usage](#usage) @@ -63,6 +65,20 @@ Raptor Templates is an extensible, streaming, asynchronous, [high performance](h +# Design Philosophy + +- __Readable:__ Templates should be as close to the output HTML as possible to keep templates readable. Cryptic syntax and symbols should be avoided. +- __Simple:__ The number of new concepts should be minimized to reduce the learning curve and complexity. +- __Extensible:__ The template engine should be easily extensible at both compile time and runtime. +- __High Performance:__ Runtime and compiled output should be optimized for low CPU and memory usage and have a small footprint. All expressions should be native JavaScript to avoid runtime interpretation. +- __Asynchronous and Streaming Output:__ It should be possible to render HTML out-of-order, but the output HTML should be streamed out in the correct order. This minimizes idle time and reduces the time to first byte. +- __Intuitive:__ The templating engine should introduce as few surprises as possible. +- __Browser and Server Compatibility:__ Templates should compile down to JavaScript that can be executed on both the server and the client. +- __Debuggable:__ Compiled JavaScript should be debuggable and readable. +- __Compile-Time Checks:__ Syntax, custom tags and custom attributes should be validated at compile-time. +- __Tools Support:__ Tools should be enabled to offer auto-completion and validation for improved productivity and safety. +- __Modular:__ Runtime and compiled templates should be based on CommonJS modules for improved dependency management. Template dependencies (such as custom tags) should resolved based on a template's file system path instead of relying on a shared registry. + # Sample A basic template with text replacement, looping and conditionals is shown below: diff --git a/compiler/lib/ElementNode.js b/compiler/lib/ElementNode.js index c15782a02..7e68c9d67 100644 --- a/compiler/lib/ElementNode.js +++ b/compiler/lib/ElementNode.js @@ -20,7 +20,6 @@ var objects = require('raptor-objects'); 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, namespace, prefix) { @@ -209,7 +208,7 @@ ElementNode.prototype = { var attrParts = []; var hasExpression = false; var invalidAttr = false; - ExpressionParser.parse(attr.value, { + template.parseExpression(attr.value, { text: function (text, escapeXml) { attrParts.push({ text: text, @@ -228,6 +227,7 @@ ElementNode.prototype = { this.addError('Invalid expression found in attribute "' + name + '". ' + message); } }, this); + if (invalidAttr) { template.text(name + '="' + escapeXmlAttr(attr.value) + '"'); } else { diff --git a/compiler/lib/EscapeXmlContext.js b/compiler/lib/EscapeXmlContext.js index 515767f83..0fa140e57 100644 --- a/compiler/lib/EscapeXmlContext.js +++ b/compiler/lib/EscapeXmlContext.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -module.exports = require('raptor-util').makeEnum([ - 'Element', - 'Attribute' -]); \ No newline at end of file +module.exports = { + 'ELEMENT': 'ELEMENT', + 'ATTRIBUTE': 'ATTRIBUTE' +}; \ No newline at end of file diff --git a/compiler/lib/Node.js b/compiler/lib/Node.js index 703d5c6df..2714a9df8 100644 --- a/compiler/lib/Node.js +++ b/compiler/lib/Node.js @@ -17,9 +17,9 @@ var createError = require('raptor-util').createError; var forEachEntry = require('raptor-util').forEachEntry; var extend = require('raptor-util').extend; - var isArray = Array.isArray; -var isEmpty = require('raptor-objects').isEmpty; +var EscapeXmlContext = require('./EscapeXmlContext'); + function Node(nodeType) { if (!this.nodeType) { this._isRoot = false; @@ -39,7 +39,13 @@ function Node(nodeType) { this.properties = {}; } } + +Node.isNode = function(node) { + return node.__NODE === true; +}; + Node.prototype = { + setRoot: function (isRoot) { this._isRoot = isRoot; }, @@ -343,6 +349,7 @@ Node.prototype = { } return true; }, + __NODE: true, isTextNode: function () { return false; }, @@ -436,7 +443,7 @@ Node.prototype = { childNode.setEscapeXmlBodyText(this.isEscapeXmlBodyText() !== false); } if (childNode.getEscapeXmlContext() == null) { - childNode.setEscapeXmlContext(this.getEscapeXmlContext() || require('./EscapeXmlContext').Element); + childNode.setEscapeXmlContext(this.getEscapeXmlContext() || require('./EscapeXmlContext').ELEMENT); } childNode.generateCode(template); }, this); @@ -489,6 +496,10 @@ Node.prototype = { return this.escapeXmlBodyText; }, setEscapeXmlContext: function (escapeXmlContext) { + if (typeof escapeXmlContext === 'string') { + escapeXmlContext = EscapeXmlContext[escapeXmlContext.toUpperCase()]; + } + this.escapeXmlContext = escapeXmlContext; }, getEscapeXmlContext: function () { diff --git a/compiler/lib/Taglib.js b/compiler/lib/Taglib.js deleted file mode 100644 index 3aa7131e1..000000000 --- a/compiler/lib/Taglib.js +++ /dev/null @@ -1,257 +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. - */ - -'use strict'; -var forEachEntry = require('raptor-util').forEachEntry; -var ok = require('assert').ok; -var makeClass = require('raptor-util').makeClass; - -function Taglib(id) { - ok(id, '"id" expected'); - this.id = id; - this.dirname = null; - this.tags = {}; - this.textTransformers = []; - this.attributes = {}; - this.patternAttributes = []; - this.inputFilesLookup = {}; -} - -Taglib.prototype = { - - addInputFile: function(path) { - this.inputFilesLookup[path] = true; - }, - - getInputFiles: function() { - return Object.keys(this.inputFilesLookup); - }, - - addAttribute: function (attribute) { - if (attribute.pattern) { - this.patternAttributes.push(attribute); - } else if (attribute.name) { - this.attributes[attribute.name] = attribute; - } else { - throw new Error('Invalid attribute: ' + require('util').inspect(attribute)); - } - }, - getAttribute: function (name) { - var attribute = this.attributes[name]; - if (!attribute) { - for (var i = 0, len = this.patternAttributes.length; i < len; i++) { - var patternAttribute = this.patternAttributes[i]; - if (patternAttribute.pattern.test(name)) { - attribute = patternAttribute; - } - } - } - return attribute; - }, - addTag: function (tag) { - ok(arguments.length === 1, 'Invalid args'); - ok(tag.name, '"tag.name" is required'); - this.tags[tag.name] = tag; - tag.taglibId = this.id; - }, - addTextTransformer: function (transformer) { - this.textTransformers.push(transformer); - }, - forEachTag: function (callback, thisObj) { - forEachEntry(this.tags, function (key, tag) { - callback.call(thisObj, tag); - }, this); - } -}; - -Taglib.Tag = makeClass({ - $init: function(taglib) { - this.taglibId = taglib ? taglib.id : null; - this.renderer = null; - this.nodeClass = null; - this.template = null; - this.attributes = {}; - this.transformers = {}; - this.nestedVariables = {}; - this.importedVariables = {}; - this.patternAttributes = []; - }, - inheritFrom: function (superTag) { - var subTag = this; - /* - * Have the sub tag inherit any properties from the super tag that are not in the sub tag - */ - forEachEntry(superTag, function (k, v) { - if (subTag[k] === undefined) { - subTag[k] = v; - } - }); - function inheritProps(sub, sup) { - forEachEntry(sup, function (k, v) { - if (!sub[k]) { - sub[k] = v; - } - }); - } - [ - 'attributes', - 'transformers', - 'nestedVariables', - 'importedVariables' - ].forEach(function (propName) { - inheritProps(subTag[propName], superTag[propName]); - }); - subTag.patternAttributes = superTag.patternAttributes.concat(subTag.patternAttributes); - }, - forEachVariable: function (callback, thisObj) { - forEachEntry(this.nestedVariables, function (key, variable) { - callback.call(thisObj, variable); - }); - }, - forEachImportedVariable: function (callback, thisObj) { - forEachEntry(this.importedVariables, function (key, importedVariable) { - callback.call(thisObj, importedVariable); - }); - }, - forEachTransformer: function (callback, thisObj) { - forEachEntry(this.transformers, function (key, transformer) { - callback.call(thisObj, transformer); - }); - }, - hasTransformers: function () { - /*jshint unused:false */ - for (var k in this.transformers) { - if (this.transformers.hasOwnProperty(k)) { - return true; - } - - } - return false; - }, - addAttribute: function (attr) { - if (attr.pattern) { - this.patternAttributes.push(attr); - } else { - if (attr.name === '*') { - attr.dynamicAttribute = true; - - if (attr.targetProperty === null || attr.targetProperty === '') { - attr.targetProperty = null; - - } - else if (!attr.targetProperty) { - attr.targetProperty = '*'; - } - } - - this.attributes[attr.name] = attr; - } - }, - toString: function () { - return '[Tag: <' + this.name + '@' + this.taglibId + '>]'; - }, - forEachAttribute: function (callback, thisObj) { - for (var attrName in this.attributes) { - if (this.attributes.hasOwnProperty(attrName)) { - callback.call(thisObj, this.attributes[attrName]); - } - } - }, - addNestedVariable: function (nestedVariable) { - var key = nestedVariable.nameFromAttribute ? 'attr:' + nestedVariable.nameFromAttribute : nestedVariable.name; - this.nestedVariables[key] = nestedVariable; - }, - addImportedVariable: function (importedVariable) { - var key = importedVariable.targetProperty; - this.importedVariables[key] = importedVariable; - }, - addTransformer: function (transformer) { - var key = transformer.path; - transformer.taglibId = this.taglibId; - this.transformers[key] = transformer; - } -}); - -Taglib.Attribute = makeClass({ - $init: function(name) { - this.name = name; - this.type = null; - this.required = false; - this.type = 'string'; - this.allowExpressions = true; - } -}); - -Taglib.Property = makeClass({ - $init: function() { - this.name = null; - this.type = 'string'; - this.value = undefined; - } -}); - -Taglib.NestedVariable = makeClass({ - $init: function() { - this.name = null; - } -}); - -Taglib.ImportedVariable = makeClass({ - $init: function() { - this.targetProperty = null; - this.expression = null; - } -}); - -var nextTransformerId = 0; - -Taglib.Transformer = makeClass({ - $init: function() { - this.id = nextTransformerId++; - this.name = null; - this.tag = null; - this.path = null; - this.priority = null; - this.instance = null; - this.properties = {}; - }, - - getInstance: function () { - if (!this.path) { - throw new Error('Transformer class not defined for tag transformer (tag=' + this.tag + ')'); - } - - if (!this.instance) { - var Clazz = require(this.path); - if (Clazz.process) { - return Clazz; - } - - if (typeof Clazz !== 'function') { - console.error('Invalid transformer: ', Clazz); - throw new Error('Invalid transformer at path "' + this.path + '": ' + Clazz); - } - this.instance = new Clazz(); - this.instance.id = this.id; - } - return this.instance; - }, - toString: function () { - return '[Taglib.Transformer: ' + this.path + ']'; - } -}); - -module.exports = Taglib; \ No newline at end of file diff --git a/compiler/lib/TaglibLookup.js b/compiler/lib/TaglibLookup.js deleted file mode 100644 index 05ae3017a..000000000 --- a/compiler/lib/TaglibLookup.js +++ /dev/null @@ -1,236 +0,0 @@ -var ok = require('assert').ok; -var createError = require('raptor-util').createError; - -function transformerComparator(a, b) { - a = a.priority; - b = b.priority; - - if (a == null) { - a = Number.MAX_VALUE; - } - - if (b == null) { - b = Number.MAX_VALUE; - } - - return a - b; -} - -function merge(target, source) { - for (var k in source) { - if (source.hasOwnProperty(k)) { - if (target[k] && typeof target[k] === 'object' && - source[k] && typeof source[k] === 'object') { - - if (Array.isArray(target[k]) || Array.isArray(source[k])) { - - var targetArray = target[k]; - var sourceArray = source[k]; - - - if (!Array.isArray(targetArray)) { - targetArray = [targetArray]; - } - - if (!Array.isArray(sourceArray)) { - sourceArray = [sourceArray]; - } - - target[k] = [].concat(targetArray).concat(sourceArray); - } else { - var Ctor = target[k].constructor; - var newTarget = new Ctor(); - merge(newTarget, target[k]); - merge(newTarget, source[k]); - target[k] = newTarget; - } - - } else { - target[k] = source[k]; - } - } - } - - return target; -} - -function TaglibLookup() { - this.merged = {}; - this.taglibsById = {}; - this._inputFiles = null; -} - -TaglibLookup.prototype = { - - - addTaglib: function (taglib) { - ok(taglib, '"taglib" is required'); - ok(taglib.id, '"taglib.id" expected'); - - if (this.taglibsById.hasOwnProperty(taglib.id)) { - return; - } - - this.taglibsById[taglib.id] = taglib; - - merge(this.merged, taglib); - }, - - getTag: function (element) { - if (typeof element === 'string') { - element = { - localName: element - }; - } - var tags = this.merged.tags; - if (!tags) { - return; - } - - var tagKey = element.namespace ? element.namespace + ':' + element.localName : element.localName; - return tags[tagKey]; - }, - - getAttribute: function (element, attr) { - - if (typeof element === 'string') { - element = { - localName: element - }; - } - - if (typeof attr === 'string') { - attr = { - localName: attr - }; - } - - var tags = this.merged.tags; - if (!tags) { - return; - } - - var tagKey = element.namespace ? element.namespace + ':' + element.localName : element.localName; - - var tag = tags[tagKey]; - if (!tag) { - tag = tags['*']; - - if (!tag) { - return; - } - } - - var attrKey = attr.namespace ? attr.namespace + ':' + attr.localName : attr.localName; - - function findAttribute(attributes) { - var attribute = attributes[attrKey]; - if (attribute === undefined) { - if (tag.patternAttributes) { - for (var i = 0, len = tag.patternAttributes.length; i < len; i++) { - var patternAttribute = tag.patternAttributes[i]; - if (patternAttribute.pattern.test(attrKey)) { - attribute = patternAttribute; - break; - } - } - } - - if (attribute === undefined) { - attribute = tag.attributes['*']; - } - } - - return attribute; - } - - - var attribute = findAttribute(tag.attributes); - - if (attribute === null) { - // This is an imported attribute - attribute = findAttribute(this.merged.attributes); - } - - return attribute; - }, - forEachNodeTransformer: function (node, callback, thisObj) { - /* - * Based on the type of node we have to choose how to transform it - */ - if (node.isElementNode()) { - this.forEachTagTransformer(node, callback, thisObj); - } else if (node.isTextNode()) { - this.forEachTextTransformer(callback, thisObj); - } - }, - forEachTagTransformer: function (element, callback, thisObj) { - if (typeof element === 'string') { - element = { - localName: element - }; - } - - var tagKey = element.namespace ? element.namespace + ':' + element.localName : element.localName; - /* - * If the node is an element node then we need to find all matching - * transformers based on the URI and the local name of the element. - */ - - var transformers = []; - - function addTransformer(transformer) { - if (!transformer || !transformer.getInstance) { - throw createError(new Error('Invalid transformer')); - } - - transformers.push(transformer); - } - - /* - * Handle all of the transformers for all possible matching transformers. - * - * Start with the least specific and end with the most specific. - */ - - if (this.merged.tags[tagKey]) { - this.merged.tags[tagKey].forEachTransformer(addTransformer); - } - - if (this.merged.tags['*']) { - this.merged.tags['*'].forEachTransformer(addTransformer); - } - - transformers.sort(transformerComparator); - - transformers.forEach(callback, thisObj); - }, - forEachTextTransformer: function (callback, thisObj) { - this.merged.textTransformers.sort(transformerComparator); - this.merged.textTransformers.forEach(callback, thisObj); - }, - getInputFiles: function() { - if (!this._inputFiles) { - var inputFilesSet = {}; - - for (var taglibId in this.taglibsById) { - if (this.taglibsById.hasOwnProperty(taglibId)) { - - var taglibInputFiles = this.taglibsById[taglibId].getInputFiles(); - var len = taglibInputFiles.length; - if (len) { - for (var i=0; i", '', /*, {, }, ; -var tokensRegExp = /"(?:[^"]|\\")*"|'(?:[^'])|(\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/)|(\/\/.*)|[\{\};]/g; - -function extractTagDef(code) { - - var startMatches = tagStartRegExp.exec(code); - - var tagDefStart; - var tagDefEnd; - - if (startMatches) { - tagDefStart = startMatches.index + startMatches[1].length; - var nextTokenMatches; - tokensRegExp.lastIndex = tagDefStart; - var depth = 0; - - while ((nextTokenMatches = tokensRegExp.exec(code))) { - if (nextTokenMatches[0] === '{') { - depth++; - continue; - } else if (nextTokenMatches[0] === '}') { - if (--depth === 0) { - tagDefEnd = tokensRegExp.lastIndex; - break; - } - } - else if (nextTokenMatches[0] === ';') { - tagDefEnd = nextTokenMatches.index; - break; - } - } - - if (tagDefStart != null && tagDefEnd != null) { - var jsTagDef = code.substring(tagDefStart, tagDefEnd); - var tagDefObject = eval('(' + jsTagDef + ')'); - return tagDefObject; - } - } else { - return null; - } -} - -exports.extractTagDef = extractTagDef; \ No newline at end of file diff --git a/compiler/lib/taglib-loader.js b/compiler/lib/taglib-loader.js deleted file mode 100644 index 46df5f53e..000000000 --- a/compiler/lib/taglib-loader.js +++ /dev/null @@ -1,393 +0,0 @@ -var fs = require('fs'); -var ok = require('assert').ok; -var nodePath = require('path'); -var Taglib = require('./Taglib'); -var cache = {}; -var forEachEntry = require('raptor-util').forEachEntry; -var raptorRegexp = require('raptor-regexp'); -var tagDefFromCode = require('./tag-def-from-code'); -var resolve = require('raptor-modules/resolver').serverResolveRequire; -var propertyHandlers = require('property-handlers'); - -function buildAttribute(attr, attrProps, path) { - - - propertyHandlers(attrProps, { - type: function(value) { - attr.type = value; - }, - targetProperty: function(value) { - attr.targetProperty = value; - }, - defaultValue: function(value) { - attr.defaultValue = value; - }, - pattern: function(value) { - if (value === true) { - var patternRegExp = raptorRegexp.simple(attr.name); - attr.pattern = patternRegExp; - } - }, - allowExpressions: function(value) { - attr.allowExpressions = value; - }, - preserveName: function(value) { - attr.preserveName = value; - }, - required: function(value) { - attr.required = value === true; - }, - removeDashes: function(value) { - attr.removeDashes = value === true; - } - }, path); - - return attr; -} - -function handleAttributes(value, parent, path) { - forEachEntry(value, function(attrName, attrProps) { - var attr = new Taglib.Attribute(attrName); - - if (attrProps == null) { - attrProps = { - type: 'string' - }; - } - else if (typeof attrProps === 'string') { - attrProps = { - type: attrProps - }; - } - - buildAttribute(attr, attrProps, '"' + attrName + '" attribute as part of ' + path); - - parent.addAttribute(attr); - }); -} - -function buildTag(tagObject, path, taglib, dirname) { - ok(tagObject); - ok(typeof path === 'string'); - ok(taglib); - ok(typeof dirname === 'string'); - - var tag = new Taglib.Tag(taglib); - - propertyHandlers(tagObject, { - name: function(value) { - tag.name = value; - }, - - renderer: function(value) { - var path = resolve(value, dirname); - if (!fs.existsSync(path)) { - throw new Error('Renderer at path "' + path + '" does not exist.'); - } - - tag.renderer = path; - }, - template: function(value) { - var path = nodePath.resolve(dirname, value); - if (!fs.existsSync(path)) { - throw new Error('Template at path "' + path + '" does not exist.'); - } - - tag.template = path; - }, - attributes: function(value) { - handleAttributes(value, tag, path); - }, - nodeClass: function(value) { - var path = resolve(value, dirname); - if (!fs.existsSync(path)) { - throw new Error('Node module at path "' + path + '" does not exist.'); - } - - tag.nodeClass = path; - }, - transformer: function(value) { - var transformer = new Taglib.Transformer(); - - if (typeof value === 'string') { - value = { - path: value - }; - } - - propertyHandlers(value, { - path: function(value) { - var path = resolve(value, dirname); - if (!fs.existsSync(path)) { - throw new Error('Transformer at path "' + path + '" does not exist.'); - } - - transformer.path = path; - }, - - priority: function(value) { - transformer.priority = value; - }, - - name: function(value) { - transformer.name = value; - }, - - properties: function(value) { - var properties = transformer.properties || (transformer.properties = {}); - for (var k in value) { - if (value.hasOwnProperty(k)) { - properties[k] = value[k]; - } - } - } - - }, 'transformer in ' + path); - - ok(transformer.path, '"path" is required for transformer'); - - tag.addTransformer(transformer); - }, - - 'var': function(value) { - tag.addNestedVariable({ - name: value - }); - }, - vars: function(value) { - if (value) { - value.forEach(function(v, i) { - var nestedVariable; - - if (typeof v === 'string') { - nestedVariable = { - name: v - }; - } else { - nestedVariable = {}; - - propertyHandlers(v, { - - name: function(value) { - nestedVariable.name = value; - }, - - nameFromAttribute: function(value) { - nestedVariable.nameFromAttribute = value; - } - - }, 'var at index ' + i); - - if (!nestedVariable.name && !nestedVariable.nameFromAttribute) { - throw new Error('The "name" or "name-from-attribute" attribute is required for a nested variable'); - } - } - - tag.addNestedVariable(nestedVariable); - }); - } - }, - importVar: function(value) { - forEachEntry(value, function(varName, varValue) { - var importedVar = { - targetProperty: varName - }; - - var expression = varValue; - - if (!expression) { - expression = varName; - } - else if (typeof expression === 'object') { - expression = expression.expression; - } - - if (!expression) { - throw new Error('Invalid "import-var": ' + require('util').inspect(varValue)); - } - - importedVar.expression = expression; - tag.addImportedVariable(importedVar); - }); - } - }, path); - - return tag; -} - -/** - * @param {String} tagsConfigPath path to tag definition file - * @param {String} tagsConfigDirname path to directory of tags config file (should be path.dirname(tagsConfigPath)) - * @param {String} dir the path to directory to scan - * @param {String} taglib the taglib that is being loaded - */ -function scanTagsDir(tagsConfigPath, tagsConfigDirname, dir, taglib) { - dir = nodePath.resolve(tagsConfigDirname, dir); - var children = fs.readdirSync(dir); - for (var i=0, len=children.length; i tag in ' + taglib.id; - } - - - var tag = buildTag(tagObject, path, taglib, tagDirname); - if (tag.name === undefined) { - tag.name = tagName; - } - taglib.addTag(tag); - }); - }, - tagsDir: function(dir) { - - if (Array.isArray(dir)) { - for (var i = 0; i < dir.length; i++) { - scanTagsDir(path, dirname, dir[i], taglib); - } - } else { - scanTagsDir(path, dirname, dir, taglib); - } - }, - textTransformer: function(value) { - var transformer = new Taglib.Transformer(); - - if (typeof value === 'string') { - value = { - path: value - }; - } - - propertyHandlers(value, { - path: function(value) { - var path = resolve(value, dirname); - if (!fs.existsSync(path)) { - throw new Error('Transformer at path "' + path + '" does not exist.'); - } - - transformer.path = path; - } - - }, 'text-transformer in ' + path); - - ok(transformer.path, '"path" is required for transformer'); - - taglib.addTextTransformer(transformer); - } - }, path); - - taglib.id = path; - - cache[path] = taglib; - - return taglib; -} - -function loadTaglibXml(taglibXml, path) { - var TaglibXmlLoader = require('./TaglibXmlLoader'); - var taglib = TaglibXmlLoader.load(taglibXml, path); - taglib.id = path; - return taglib; -} - -function loadTaglibXmlFromFile(path) { - var src = fs.readFileSync(path, {encoding: 'utf8'}); - return loadTaglibXml(src, path); -} - -exports.load = load; -exports.loadTaglibXml = loadTaglibXml; -exports.loadTaglibXmlFromFile = loadTaglibXmlFromFile; diff --git a/compiler/lib/taglib-lookup.js b/compiler/lib/taglib-lookup.js deleted file mode 100644 index a593ff204..000000000 --- a/compiler/lib/taglib-lookup.js +++ /dev/null @@ -1,116 +0,0 @@ -var nodePath = require('path'); -var fs = require('fs'); -var taglibLoader = require('./taglib-loader'); -var existsCache = {}; -var File = require('raptor-files/File'); -var TaglibLookup = require('./TaglibLookup'); - -exports.coreTaglibs = []; - -var lookupCache = {}; -var discoverCache = {}; - -function existsCached(path) { - var exists = existsCache[path]; - if (exists === undefined) { - exists = fs.existsSync(path); - existsCache = exists; - } - return exists; -} - -function tryDir(dirname, discovered) { - var taglibPath = nodePath.join(dirname, 'raptor-taglib.json'); - if (existsCached(taglibPath)) { - var taglib = taglibLoader.load(taglibPath); - - discovered.push(taglib); - } -} - -function tryNodeModules(parent, discovered) { - if (nodePath.basename(parent) === 'node_modules') { - return; - } - - var nodeModulesDir = nodePath.join(parent, 'node_modules'); - if (existsCached(nodeModulesDir)) { - var file = new File(nodeModulesDir); - var children = file.listFiles(); - children.forEach(function(moduleDir) { - if (moduleDir.isDirectory()) { - var taglibPath = nodePath.join(moduleDir.getAbsolutePath(), 'raptor-taglib.json'); - if (existsCached(taglibPath)) { - var taglib = taglibLoader.load(taglibPath); - taglib.moduleName = moduleDir.getName(); - discovered.push(taglib); - } - } - }); - } -} - -function discoverHelper(dirname, discovered) { - tryDir(dirname, discovered); - tryNodeModules(dirname, discovered); - - var parent = nodePath.dirname(dirname); - if (parent && parent !== dirname) { - discoverHelper(parent, discovered); - } -} - -function discover(dirname) { - - var discovered = discoverCache[dirname]; - if (discovered) { - return discovered; - } - - discovered = []; - - discoverHelper(dirname, discovered); - - discovered = discovered.concat(exports.coreTaglibs); - - - - discoverCache[dirname] = discovered; - - return discovered; -} - -function buildLookup(dirname) { - var taglibs = discover(dirname); - - var lookupCacheKey = taglibs - .map(function(taglib) { - return taglib.id; - }) - .join(','); - - var lookup = lookupCache[lookupCacheKey]; - if (lookup === undefined) { - lookup = new TaglibLookup(); - - for (var i=taglibs.length-1; i>=0; i--) { - lookup.addTaglib(taglibs[i]); - } - - lookupCache[lookupCacheKey] = lookup; - } - - return lookup; -} - -function addCoreTaglib(taglib) { - exports.coreTaglibs.push(taglib); -} - -addCoreTaglib(taglibLoader.load(nodePath.join(__dirname, '../../taglibs/core/raptor-taglib.json'))); -addCoreTaglib(taglibLoader.load(nodePath.join(__dirname, '../../taglibs/html/raptor-taglib.json'))); -addCoreTaglib(taglibLoader.load(nodePath.join(__dirname, '../../taglibs/caching/raptor-taglib.json'))); -addCoreTaglib(taglibLoader.load(nodePath.join(__dirname, '../../taglibs/layout/raptor-taglib.json'))); -addCoreTaglib(taglibLoader.load(nodePath.join(__dirname, '../../taglibs/async/raptor-taglib.json'))); - -exports.buildLookup = buildLookup; \ No newline at end of file diff --git a/package.json b/package.json index 525aa9842..1cf577caf 100644 --- a/package.json +++ b/package.json @@ -32,18 +32,22 @@ "raptor-xml": "^0.2.0-beta", "raptor-objects": "^0.2.0-beta", "raptor-ecma": "^0.2.0-beta", - "raptor-files": "^0.2.0-beta", "htmlparser2": "~3.5.1", "char-props": "~0.1.5", "raptor-promises": "^0.2.0-beta", "raptor-args": "^0.1.9-beta", "minimatch": "^0.2.14", - "property-handlers": "^0.2.1-beta" + "property-handlers": "^0.2.1-beta", + "raptor-taglibs": "^0.2.0-beta", + "raptor-taglib-async": "^0.2.0-beta", + "raptor-taglib-caching": "^0.2.0-beta", + "raptor-taglib-core": "^0.2.0-beta", + "raptor-taglib-html": "^0.2.0-beta", + "raptor-taglib-layout": "^0.2.0-beta" }, "devDependencies": { "mocha": "~1.15.1", - "chai": "~1.8.1", - "raptor-cache": "^0.2.0-beta" + "chai": "~1.8.1" }, "license": "Apache License v2.0", "bin": { diff --git a/runtime/lib/helpers.js b/runtime/lib/helpers.js index 470dfee5f..3a2fb3a84 100644 --- a/runtime/lib/helpers.js +++ b/runtime/lib/helpers.js @@ -77,8 +77,12 @@ module.exports = { a: attr, as: attrs, + l: function(path) { + return typeof path === 'string' ? runtime.load(path) : path; + }, /* Helpers that require a context below: */ + t: function (context, handler, props, body, namespacedProps) { if (!props) { props = {}; @@ -108,10 +112,7 @@ module.exports = { } }; }, - i: function(context, path, data, require) { - if (typeof require === 'function') { - path = require.resolve(path); - } + i: function(context, path, data) { runtime.render(path, data, context); return this; }, diff --git a/runtime/lib/raptor-templates.js b/runtime/lib/raptor-templates.js index 364921679..1e615a0ce 100644 --- a/runtime/lib/raptor-templates.js +++ b/runtime/lib/raptor-templates.js @@ -28,6 +28,24 @@ var cache = {}; exports.Context = Context; +function load(templatePath) { + var templateFunc; + + if (typeof templatePath === 'string') { + templateFunc = cache[templatePath]; + if (!templateFunc) { + templateFunc = cache[templatePath] = loader(templatePath)(helpers); + } + } else { + // Instead of a path, assume we got a compiled template module + templateFunc = templatePath._ || (templatePath._ = templatePath(helpers)); + } + + return templateFunc; +} + +exports.load = load; + exports.render = function (templatePath, data, callback, context) { if (typeof callback !== 'function') { // A context object was provided instead of a callback @@ -42,20 +60,7 @@ exports.render = function (templatePath, data, callback, context) { shouldEnd = true; } - var templateFunc; - - if (typeof templatePath === 'string') { - templateFunc = cache[templatePath]; - if (!templateFunc) { - templateFunc = cache[templatePath] = loader(templatePath)(helpers); - } - } else { - // Instead of a path, assume we got a compiled template module - templateFunc = templatePath._ || (templatePath._ = templatePath(helpers)); - } - - - templateFunc(data || {}, context); //Invoke the template rendering function with the required arguments + load(templatePath)(data || {}, context); //Invoke the template rendering function with the required arguments if (callback) { context diff --git a/taglibs/async/AsyncFragmentTagTransformer.js b/taglibs/async/AsyncFragmentTagTransformer.js deleted file mode 100644 index d5b6e3cb6..000000000 --- a/taglibs/async/AsyncFragmentTagTransformer.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; -var varNameRegExp = /^[A-Za-z_][A-Za-z0-9_]*$/; -module.exports = { - process: function (node, compiler, template) { - var varName = node.getAttribute('var') || node.getAttribute('data-provider') || node.getAttribute('dependency'); - if (varName) { - if (!varNameRegExp.test(varName)) { - node.addError('Invalid variable name of "' + varName + '"'); - return; - } - } else { - node.addError('Either "var" or "data-provider" is required'); - return; - } - - - var argProps = []; - var propsToRemove = []; - node.forEachProperty(function (name, value) { - if (name.startsWith('arg-')) { - var argName = name.substring('arg-'.length); - argProps.push(JSON.stringify(argName) + ': ' + value); - propsToRemove.push(name); - } - }); - propsToRemove.forEach(function (propName) { - node.removeProperty(propName); - }); - var argString; - if (argProps.length) { - argString = '{' + argProps.join(', ') + '}'; - } - var arg = node.getProperty('arg'); - if (arg) { - var extendFuncName = template.getStaticHelperFunction('extend', 'xt'); - argString = extendFuncName + '(' + arg + ', ' + argString + ')'; - } - if (argString) { - node.setProperty('arg', template.makeExpression(argString)); - } - } -}; \ No newline at end of file diff --git a/taglibs/async/async-fragment-tag.js b/taglibs/async/async-fragment-tag.js deleted file mode 100644 index 09ebbbf6a..000000000 --- a/taglibs/async/async-fragment-tag.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; -var raptorDataProviders = require('raptor-data-providers'); - -module.exports = { - render: function (input, context) { - var dataProvider = input.dataProvider; - - var dataProviders = raptorDataProviders.forContext(context, false /* don't create if missing */); - - var arg = input.arg || {}; - - arg.context = context; - var asyncContext = context.beginAsync(input.timeout); - - function onError(e) { - asyncContext.error(e || 'Async fragment failed'); - } - - function renderBody(data) { - try { - if (input.invokeBody) { - input.invokeBody(asyncContext, data); - } - asyncContext.end(); - } catch (e) { - onError(e); - } - } - - var method = input.method; - if (method) { - dataProvider = dataProvider[method].bind(dataProvider); - } - - try { - dataProviders.requestData(dataProvider, arg, function(err, data) { - if (err) { - return onError(err); - } - - renderBody(data); - }); - } catch (e) { - onError(e); - } - } -}; \ No newline at end of file diff --git a/taglibs/async/optimizer.json b/taglibs/async/optimizer.json deleted file mode 100644 index 8f3feb19a..000000000 --- a/taglibs/async/optimizer.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "package": "raptor/render-context/async" - }, - "AsyncFragmentTag.js" - ] -} \ No newline at end of file diff --git a/taglibs/async/raptor-taglib.json b/taglibs/async/raptor-taglib.json deleted file mode 100644 index 44d353fbe..000000000 --- a/taglibs/async/raptor-taglib.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "tags": { - "async-fragment": { - "renderer": "./async-fragment-tag", - "attributes": { - "data-provider": { - "type": "string" - }, - "arg": { - "type": "expression", - "preserve-name": true - }, - "arg-*": { - "pattern": true, - "type": "string", - "preserve-name": true - }, - "var": { - "type": "identifier" - }, - "timeout": { - "type": "integer" - }, - "method": { - "type": "string" - } - }, - "vars": [ - "context", - { - "name-from-attribute": "var OR dependency OR data-provider|keep" - } - ], - "transformer": "./AsyncFragmentTagTransformer" - } - } -} \ No newline at end of file diff --git a/taglibs/caching/CachedFragmentTag.js b/taglibs/caching/CachedFragmentTag.js deleted file mode 100644 index 0a15e7134..000000000 --- a/taglibs/caching/CachedFragmentTag.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; -var promiseUtil = require('raptor-promises/util'); - -module.exports = { - render: function (input, context) { - var attributes = context.attributes; - var cacheProvider = attributes.cacheProvider; - var cache; - - var cacheKey = input.cacheKey; - if (!cacheKey) { - throw new Error('cache-key is required for '); - } - if (!cacheProvider) { - var raptorCacheModulePath; - try { - raptorCacheModulePath = require.resolve('raptor-cache'); - } - catch(e) { - throw new Error('The "raptor-cache" module should be installed as an application-level dependency when using caching tags'); - } - cacheProvider = require(raptorCacheModulePath).getDefaultProvider(); - } - cache = cacheProvider.getCache(input.cacheName); - var cachePromise = cache.get( - cacheKey, - { - builder: function() { - var result = context.captureString(function () { - if (input.invokeBody) { - input.invokeBody(); - } - }); - return result; - } - }); - - var asyncContext = context.beginAsync(); - - promiseUtil.immediateThen( - cachePromise, - function (result) { - asyncContext.end(result); - }, - function (e) { - asyncContext.error(e); - }); - } -}; \ No newline at end of file diff --git a/taglibs/caching/raptor-taglib.json b/taglibs/caching/raptor-taglib.json deleted file mode 100644 index aea67a0a8..000000000 --- a/taglibs/caching/raptor-taglib.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "tags": { - "cached-fragment": { - "renderer": "./CachedFragmentTag", - "attributes": { - "cache-key": { - "type": "string" - }, - "cache-name": { - "type": "string" - } - } - } - } -} \ No newline at end of file diff --git a/taglibs/core/AssignNode.js b/taglibs/core/AssignNode.js deleted file mode 100644 index 173b03b81..000000000 --- a/taglibs/core/AssignNode.js +++ /dev/null @@ -1,43 +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. - */ -'use strict'; -var varNameRegExp = /^[A-Za-z_][A-Za-z0-9_]*$/; -function AssignNode(props) { - AssignNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -AssignNode.prototype = { - doGenerateCode: function (template) { - var varName = this.getProperty('var'); - var value = this.getProperty('value'); - if (!varName) { - this.addError('"var" attribute is required'); - } else if (!varNameRegExp.test(varName)) { - this.addError('Invalid variable name of "' + varName + '"'); - varName = null; - } - if (!value) { - this.addError('"value" attribute is required'); - } - if (varName) { - template.statement(varName + '=' + value + ';'); - } - } -}; -require('raptor-util').inherit(AssignNode, require('../../compiler').Node); -module.exports = AssignNode; \ No newline at end of file diff --git a/taglibs/core/ChooseNode.js b/taglibs/core/ChooseNode.js deleted file mode 100644 index b899cff25..000000000 --- a/taglibs/core/ChooseNode.js +++ /dev/null @@ -1,65 +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. - */ -'use strict'; -var strings = require('raptor-strings'); -var WhenNode = require('./WhenNode'); -var OtherwiseNode = require('./OtherwiseNode'); -function ChooseNode(props) { - ChooseNode.$super.call(this); -} -ChooseNode.prototype = { - doGenerateCode: function (template) { - var otherwiseNode = null; - var foundWhenNode = false; - var allowedNodes = []; - this.forEachChild(function (child) { - if (child.isTextNode()) { - if (!strings.isEmpty(child.getText())) { - this.addError('Static text "' + strings.trim(child.getText()) + '" is not allowed in ' + this.toString() + ' tag.'); - } - } else if (child.getNodeClass() === WhenNode) { - if (otherwiseNode) { - this.addError(otherwiseNode + ' tag must be last child of tag ' + this + '.'); - return; - } - if (!foundWhenNode) { - foundWhenNode = true; - child.firstWhen = true; - } - allowedNodes.push(child); - } else if (child.getNodeClass() === OtherwiseNode) { - if (otherwiseNode) { - this.addError('More than one ' + otherwiseNode + ' tag is not allowed as child of tag ' + this + '.'); - return; - } - otherwiseNode = child; - allowedNodes.push(otherwiseNode); - } else { - this.addError(child + ' tag is not allowed as child of tag ' + this + '.'); - child.generateCode(template); //Generate the code for the children so that we can still show errors to the user for nested nodes - } - }, this); - allowedNodes.forEach(function (child, i) { - child.hasElse = i < allowedNodes.length - 1; - child.generateCode(template); - }); - if (!foundWhenNode) { - this.addError('' + otherwiseNode + ' tag is required to have at least one sibling tag.'); - } - } -}; -require('raptor-util').inherit(ChooseNode, require('../../compiler').Node); -module.exports = ChooseNode; \ No newline at end of file diff --git a/taglibs/core/CoreTagTransformer.js b/taglibs/core/CoreTagTransformer.js deleted file mode 100644 index 17815b4d9..000000000 --- a/taglibs/core/CoreTagTransformer.js +++ /dev/null @@ -1,346 +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. - */ -'use strict'; -function removeDashes(str) { - return str.replace(/-([a-z])/g, function (match, lower) { - return lower.toUpperCase(); - }); -} -var extend = require('raptor-util').extend; - -var WriteNode = require('./WriteNode'); -var ForNode = require('./ForNode'); -var IfNode = require('./IfNode'); -var ElseIfNode = require('./ElseIfNode'); -var ElseNode = require('./ElseNode'); -var WithNode = require('./WithNode'); -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 EscapeXmlContext = require('../../compiler').EscapeXmlContext; -var resolver = require('raptor-modules/resolver'); - -function getPropValue(value, type, allowExpressions) { - return TypeConverter.convert(value, type, allowExpressions); -} - -function CoreTagTransformer() { -} - -CoreTagTransformer.prototype = { - process: function (node, compiler, template) { - //Find and handle nested elements - this.findNestedAttrs(node, compiler, template); - var inputAttr; - var forEachNode; - var tag; - - function forEachProp(callback, thisObj) { - var foundProps = {}; - - node.forEachAttributeAnyNS(function (attr) { - var attrDef = compiler.taglibs.getAttribute(node, attr); - var type = attrDef ? attrDef.type || 'string' : 'string'; - - var value; - - 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; - } - - if (attr.value instanceof Expression) { - value = attr.value; - } else { - try { - value = getPropValue(attr.value, type, attrDef ? attrDef.allowExpressions !== false : true); - } catch (e) { - node.addError('Invalid attribute value of "' + attr.value + '" for attribute "' + attr.name + '": ' + e.message); - value = attr.value; - } - - } - 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 coreAttrHandlers = { - 'c-space': function(attr) { - this['c-whitespace'](attr); - }, - 'c-whitespace': function(attr) { - if (attr.value === 'preserve') { - node.setPreserveWhitespace(true); - } - }, - 'c-escape-xml': function(attr) { - node.setEscapeXmlBodyText(attr.value !== 'false'); - }, - 'c-parse-body-text': function(attr) { - node.parseBodyText = attr.value !== 'false'; - }, - 'c-when': function(attr) { - var whenNode = new WhenNode({ - test: new Expression(attr.value), - pos: node.getPosition() - }); - node.parentNode.replaceChild(whenNode, node); - whenNode.appendChild(node); - }, - 'c-otherwise': function(attr) { - var otherwiseNode = new OtherwiseNode({ pos: node.getPosition() }); - node.parentNode.replaceChild(otherwiseNode, node); - otherwiseNode.appendChild(node); - }, - 'c-attrs': function(attr) { - node.dynamicAttributesExpression = attr.value; - }, - 'c-for-each': function(attr) { - this['for'](attr); - }, - 'c-for': function(attr) { - var forEachProps = AttributeSplitter.parse(attr.value, { - each: { type: 'custom' }, - separator: { type: 'expression' }, - 'iterator': { type: 'expression' }, - 'status-var': { type: 'identifier' }, - 'for-loop': { - type: 'boolean', - allowExpressions: false - } - }, { - removeDashes: true, - defaultName: 'each', - errorHandler: function (message) { - node.addError('Invalid c:for attribute of "' + attr.value + '". Error: ' + message); - } - }); - forEachProps.pos = node.getPosition(); - //Copy the position property - forEachNode = new ForNode(forEachProps); - //Surround the existing node with an "forEach" node by replacing the current - //node with the new "forEach" node and then adding the current node as a child - node.parentNode.replaceChild(forEachNode, node); - forEachNode.appendChild(node); - }, - 'c-if': function(attr) { - var ifNode = new IfNode({ - test: new Expression(attr.value), - pos: node.getPosition() - }); - //Surround the existing node with an "if" node by replacing the current - //node with the new "if" node and then adding the current node as a child - node.parentNode.replaceChild(ifNode, node); - ifNode.appendChild(node); - }, - 'c-else-if': function(attr) { - var elseIfNode = new ElseIfNode({ - test: new Expression(attr.value), - pos: node.getPosition() - }); - //Surround the existing node with an "if" node by replacing the current - //node with the new "if" node and then adding the current node as a child - node.parentNode.replaceChild(elseIfNode, node); - elseIfNode.appendChild(node); - }, - 'c-else': function(attr) { - var elseNode = new ElseNode({ pos: node.getPosition() }); - //Surround the existing node with an "if" node by replacing the current - //node with the new "if" node and then adding the current node as a child - node.parentNode.replaceChild(elseNode, node); - elseNode.appendChild(node); - }, - 'c-with': function(attr) { - var withNode = new WithNode({ - vars: attr.value, - pos: node.getPosition() - }); - node.parentNode.replaceChild(withNode, node); - withNode.appendChild(node); - }, - 'c-body-content': function(attr) { - this.content(attr); - }, - 'c-content': function(attr) { - var newChild = new WriteNode({ - expression: attr.value, - pos: node.getPosition() - }); - node.removeChildren(); - node.appendChild(newChild); - }, - 'c-trim-body-indent': function(attr) { - if (attr.value === 'true') { - node.trimBodyIndent = true; - } - }, - 'c-strip': function(attr) { - if (!node.setStripExpression) { - node.addError('The c:strip directive is not allowed for target node'); - } - node.setStripExpression(attr.value); - }, - 'c-replace': function(attr) { - var replaceWriteNode = new WriteNode({ - expression: attr.value, - pos: node.getPosition() - }); - //Replace the existing node with an node that only has children - node.parentNode.replaceChild(replaceWriteNode, node); - node = replaceWriteNode; - }, - 'c-input': function(attr) { - inputAttr = attr.value; - } - }; - - node.forEachAttributeNS('', function(attr) { - - var handler = coreAttrHandlers[attr.qName]; - if (handler) { - node.removeAttribute(attr.localName); - coreAttrHandlers[attr.localName](attr); - } - }); - - 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); - } - node.addDynamicAttribute(name, value); - node.setDynamicAttributesProperty(attrDef.targetProperty); - } else { - node.setProperty(name, value); - } - }); - - } else if (tag.nodeClass) { - var NodeCompilerClass = require(tag.nodeClass); - extend(node, NodeCompilerClass.prototype); - NodeCompilerClass.call(node); - node.setNodeClass(NodeCompilerClass); - forEachProp(function (name, value) { - node.setProperty(name, value); - }); - } - } - }, - findNestedAttrs: function (node, compiler, template) { - node.forEachChild(function (child) { - if (child.qName === 'c-attr') { - this.handleAttr(child, compiler, template); - } - }, this); - }, - handleAttr: function (node, compiler, template) { - var parentNode = node.parentNode; - if (!parentNode.isElementNode()) { - node.addError(this.toString() + ' tag is not nested within an element tag.'); - return; - } - var hasValue = node.hasAttribute('value'); - var attrName = node.getAttribute('name'); - var attrValue = node.getAttribute('value'); - var attrUri = node.getAttribute('namespace') || ''; - var attrPrefix = node.getAttribute('prefix') || ''; - if (parentNode.hasAttributeNS(attrUri, attrName)) { - node.addError(node.toString() + ' tag adds duplicate attribute with name "' + attrName + '"' + (attrUri ? ' and URI "' + attrUri + '"' : '')); - return; - } - node.removeAttribute('name'); - node.removeAttribute('value'); - node.removeAttribute('namespace'); - node.removeAttribute('prefix'); - if (node.hasAttributesAnyNS()) { - var invalidAttrs = node.getAllAttributes().map(function (attr) { - return attr.qName; - }); - node.addError('Invalid attributes for tag ' + node.toString() + ': ' + invalidAttrs.join(', ')); - return; - } - //Cleanup whitespace between tags - if (node.previousSibling && node.previousSibling.isTextNode() && node.previousSibling.getText().trim() === '') { - node.previousSibling.detach(); - } - if (node.nextSibling && node.nextSibling.isTextNode() && node.nextSibling.getText().trim() === '') { - node.nextSibling.detach(); - } - if (node.nextSibling && node.nextSibling.isTextNode()) { - node.nextSibling.setText(node.nextSibling.getText().replace(/^\n\s*/, '')); - } - node.detach(); - //Remove the node out of the tree - compiler.transformTree(node, template); - if (hasValue) { - parentNode.setAttributeNS(attrUri, attrName, attrValue, attrPrefix); - } else { - node.setEscapeXmlContext(EscapeXmlContext.Attribute); - //Escape body text and expressions as attributes - parentNode.setAttributeNS(attrUri, attrName, node.getBodyContentExpression(template), attrPrefix, false); - } - } -}; -module.exports = CoreTagTransformer; \ No newline at end of file diff --git a/taglibs/core/CoreTextTransformer.js b/taglibs/core/CoreTextTransformer.js deleted file mode 100644 index 36257f610..000000000 --- a/taglibs/core/CoreTextTransformer.js +++ /dev/null @@ -1,87 +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. - */ -'use strict'; -var ExpressionParser = require('../../compiler').ExpressionParser; -var TextNode = require('../../compiler').TextNode; -var WriteNode = require('./WriteNode'); -var ScriptletNode = require('./ScriptletNode'); -function CoreTextTransformer() { -} -CoreTextTransformer.prototype = { - process: function (node, compiler) { - if (node.parentNode && node.parentNode.parseBodyText === false) { - return; //Don't try to parse expressions - } - var parts = []; - ExpressionParser.parse(node.text, { - text: function (text, escapeXml) { - parts.push({ - text: text, - escapeXml: escapeXml - }); - }, - expression: function (expression, escapeXml) { - parts.push({ - expression: expression, - escapeXml: escapeXml - }); - }, - scriptlet: function (scriptlet) { - parts.push({ scriptlet: scriptlet }); - }, - error: function (message) { - node.addError(message); - } - }, this); - if (parts.length > 0) { - var startIndex = 0; - if (parts[0].text) { - node.setText(parts[0].text); - //Update this text node to match first text part and we'll add the remaining - node.setEscapeXml(parts[0].escapeXml !== false); - startIndex = 1; - } else { - node.text = ''; - //The first part is an expression so we'll just zero out this text node - startIndex = 0; - } - var newNodes = []; - for (var i = startIndex, part, newNode; i < parts.length; i++) { - part = parts[i]; - newNode = null; - if (part.hasOwnProperty('text')) { - newNode = new TextNode(part.text, part.escapeXml !== false); - newNode.setTransformerApplied(this); //We shouldn't reprocess the new text node - } else if (part.hasOwnProperty('expression')) { - newNode = new WriteNode({ - expression: part.expression, - escapeXml: part.escapeXml !== false - }); - } else if (part.hasOwnProperty('scriptlet')) { - newNode = new ScriptletNode(part.scriptlet); - } - if (newNode) { - newNode.setPosition(node.getPosition()); - newNodes.push(newNode); - } - } - if (newNodes.length) { - node.parentNode.insertAfter(newNodes, node); - } - } - } -}; -module.exports = CoreTextTransformer; \ No newline at end of file diff --git a/taglibs/core/DefNode.js b/taglibs/core/DefNode.js deleted file mode 100644 index f68a1ff6d..000000000 --- a/taglibs/core/DefNode.js +++ /dev/null @@ -1,64 +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. - */ -'use strict'; -var strings = require('raptor-strings'); -var funcDefRegExp = /^([A-Za-z_][A-Za-z0-9_]*)(?:\(((?:[A-Za-z_][A-Za-z0-9_]*,\s*)*[A-Za-z_][A-Za-z0-9_]*)?\))?$/; -function DefNode(props) { - DefNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -DefNode.prototype = { - doGenerateCode: function (template) { - var func = this.getProperty('function'); - if (!func) { - this.addError('"function" attribute is required'); - this.generateCodeForChildren(template); - return; - } - func = strings.trim(func); - var matches = funcDefRegExp.exec(func); - if (matches) { - var name = matches[1]; - var params = matches[2] ? matches[2].split(/\s*,\s*/) : []; - var definedFunctions = template.getAttribute('core:definedFunctions'); - if (!definedFunctions) { - definedFunctions = template.setAttribute('core:definedFunctions', {}); - } - definedFunctions[name] = { - params: params, - bodyParam: this.getProperty('bodyParam') - }; - } else { - this.addError('Invalid function name of "' + func + '"'); - this.generateCodeForChildren(template); - return; - } - - if (func.indexOf('(') === -1) { - func += '()'; - } - - template.statement('function ' + func + ' {').indent(function () { - template.line('return __helpers.c(context, function() {').indent(function () { - this.generateCodeForChildren(template); - }, this).line('});'); - }, this).line('}'); - } -}; -require('raptor-util').inherit(DefNode, require('../../compiler').Node); -module.exports = DefNode; \ No newline at end of file diff --git a/taglibs/core/ElseIfNode.js b/taglibs/core/ElseIfNode.js deleted file mode 100644 index 7409a77c9..000000000 --- a/taglibs/core/ElseIfNode.js +++ /dev/null @@ -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. - */ -'use strict'; -function ElseIfNode(props) { - ElseIfNode.$super.call(this, 'c-else-if'); - if (props) { - this.setProperties(props); - } -} -ElseIfNode.prototype = { - doGenerateCode: function (template) { - var test = this.getProperty('test'); - if (!test) { - this.addError('"test" attribute is required'); - return; - } - template.line('else if (' + test + ') {').indent(function () { - this.generateCodeForChildren(template); - }, this).line('}'); - } -}; -require('raptor-util').inherit(ElseIfNode, require('../../compiler').ElementNode); -module.exports = ElseIfNode; \ No newline at end of file diff --git a/taglibs/core/ElseNode.js b/taglibs/core/ElseNode.js deleted file mode 100644 index ca8fb88ff..000000000 --- a/taglibs/core/ElseNode.js +++ /dev/null @@ -1,34 +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. - */ -'use strict'; -function ElseNode(props) { - ElseNode.$super.call(this, 'c-else'); - if (props) { - this.setProperties(props); - } -} -ElseNode.prototype = { - doGenerateCode: function (template) { - if (this.valid == null) { - return; //Don't generate code for an invalid else - } - template.line('else {').indent(function () { - this.generateCodeForChildren(template); - }, this).line('}'); - } -}; -require('raptor-util').inherit(ElseNode, require('../../compiler').ElementNode); -module.exports = ElseNode; \ No newline at end of file diff --git a/taglibs/core/ElseTagTransformer.js b/taglibs/core/ElseTagTransformer.js deleted file mode 100644 index 9cae45388..000000000 --- a/taglibs/core/ElseTagTransformer.js +++ /dev/null @@ -1,55 +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. - */ -'use strict'; -var strings = require('raptor-strings'); -function ElseTagTransformer() { -} -ElseTagTransformer.prototype = { - process: function (node, compiler) { - var curNode = node.previousSibling; - var matchingNode; - var IfNode = compiler.getNodeClass('c-if'); - var ElseIfNode = compiler.getNodeClass('c-else-if'); - var whitespaceNodes = []; - while (curNode) { - if (curNode.getNodeClass() === ElseIfNode || curNode.getNodeClass() === IfNode) { - matchingNode = curNode; - break; - } else if (curNode.isTextNode()) { - if (!strings.isEmpty(curNode.getText())) { - node.addError('Static text "' + strings.trim(curNode.getText()) + '" is not allowed before ' + node.toString() + ' tag.'); - return; - } else { - whitespaceNodes.push(curNode); - } - } else { - node.addError(curNode + ' is not allowed before ' + node.toString() + ' tag.'); - return; - } - curNode = curNode.previousSibling; - } - if (!matchingNode) { - node.addError(' or node not found immediately before ' + node.toString() + ' tag.'); - return; - } - whitespaceNodes.forEach(function (whitespaceNode) { - whitespaceNode.parentNode.removeChild(whitespaceNode); - }); - matchingNode.hasElse = true; - node.valid = true; - } -}; -module.exports = ElseTagTransformer; \ No newline at end of file diff --git a/taglibs/core/ForNode.js b/taglibs/core/ForNode.js deleted file mode 100644 index 64b369586..000000000 --- a/taglibs/core/ForNode.js +++ /dev/null @@ -1,142 +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. - */ -'use strict'; -var forEachRegEx = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s+in\s+(.+)$/; -var forEachPropRegEx = /^\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*,\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)\s+in\s+(.+)$/; -var stringify = require('raptor-json/stringify').stringify; -function parseForEach(value) { - var match = value.match(forEachRegEx); - if (match) { - return { - 'var': match[1], - 'in': match[2] - }; - } else { - match = value.match(forEachPropRegEx); - if (!match) { - throw new Error('Invalid each attribute of "' + value + '"'); - } - - return { - 'nameVar': match[1], - 'valueVar': match[2], - 'in': match[3] - }; - } -} -function ForNode(props) { - ForNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -ForNode.prototype = { - doGenerateCode: function (template) { - var each = this.getProperty('each'); - var separator = this.getProperty('separator'); - var statusVar = this.getProperty('statusVar') || this.getProperty('varStatus'); - var customIterator = this.getProperty('iterator'); - if (!each) { - this.addError('"each" attribute is required'); - this.generateCodeForChildren(template); - return; - } - var parts; - try { - parts = parseForEach(each); - } catch (e) { - this.addError(e.message); - this.generateCodeForChildren(template); - return; - } - var items = template.makeExpression(parts['in']); - var varName = parts['var']; - var nameVarName = parts.nameVar; - var valueVarName = parts.valueVar; - if (nameVarName) { - if (separator) { - this.addError('Separator is not supported when looping over properties'); - this.generateCodeForChildren(template); - return; - } - if (statusVar) { - this.addError('Loop status variable not supported when looping over properties'); - this.generateCodeForChildren(template); - return; - } - } - if (separator && !statusVar) { - statusVar = '__loop'; - } - var funcName; - var forEachParams; - if (customIterator) { - var statusVarFlag = ''; - if (statusVar) { - statusVarFlag = ', true'; - forEachParams = [ - varName, - statusVar - ]; - } else { - forEachParams = [varName]; - } - template.statement(customIterator + '(' + items + ', function(' + forEachParams.join(',') + ') {').indent(function () { - this.generateCodeForChildren(template); - }, this).line('}' + statusVarFlag + ');'); - } else if (statusVar) { - forEachParams = [ - varName, - statusVar - ]; - funcName = template.getStaticHelperFunction('forEachWithStatusVar', 'fv'); - template.statement(funcName + '(' + items + ', function(' + forEachParams.join(',') + ') {').indent(function () { - this.generateCodeForChildren(template); - if (separator) { - template.statement('if (!' + statusVar + '.isLast()) {').indent(function () { - template.write(template.isExpression(separator) ? separator.getExpression() : stringify(separator)); - }, this).line('}'); - } - }, this).line('});'); - } else { - if (this.getProperty('forLoop') === true) { - forEachParams = [ - '__array', - '__index', - '__length', - varName - ]; - template.statement(template.getStaticHelperFunction('forLoop', 'fl') + '(' + items + ', function(' + forEachParams.join(',') + ') {').indent(function () { - template.statement('for (;__index<__length;__index++) {').indent(function () { - template.statement(varName + '=__array[__index];'); - this.generateCodeForChildren(template); - }, this).line('}'); - }, this).line('});'); - } else { - forEachParams = nameVarName ? [ - nameVarName, - valueVarName - ] : [varName]; - funcName = nameVarName ? template.getStaticHelperFunction('forEachProp', 'fp') : template.getStaticHelperFunction('forEach', 'f'); - template.statement(funcName + '(' + items + ', function(' + forEachParams.join(',') + ') {').indent(function () { - this.generateCodeForChildren(template); - }, this).line('});'); - } - } - } -}; -require('raptor-util').inherit(ForNode, require('../../compiler').Node); -module.exports = ForNode; \ No newline at end of file diff --git a/taglibs/core/IfNode.js b/taglibs/core/IfNode.js deleted file mode 100644 index 31c1d1752..000000000 --- a/taglibs/core/IfNode.js +++ /dev/null @@ -1,35 +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. - */ -'use strict'; -function IfNode(props) { - IfNode.$super.call(this, 'c-if'); - if (props) { - this.setProperties(props); - } -} -IfNode.prototype = { - doGenerateCode: function (template) { - var test = this.getProperty('test'); - if (!test) { - this.addError('"test" attribute is required'); - } - template.statement('if (' + test + ') {').indent(function () { - this.generateCodeForChildren(template); - }, this).line('}'); - } -}; -require('raptor-util').inherit(IfNode, require('../../compiler').ElementNode); -module.exports = IfNode; \ No newline at end of file diff --git a/taglibs/core/IncludeNode.js b/taglibs/core/IncludeNode.js deleted file mode 100644 index f7b700c12..000000000 --- a/taglibs/core/IncludeNode.js +++ /dev/null @@ -1,83 +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. - */ -'use strict'; -var stringify = require('raptor-json/stringify'); -var nodePath = require('path'); -var fs = require('fs'); - -var extend = require('raptor-util').extend; -function IncludeNode(props) { - IncludeNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -IncludeNode.convertNode = function (node, template) { - extend(node, IncludeNode.prototype); - IncludeNode.call(node); - node.setProperty('template', stringify(template)); -}; -IncludeNode.prototype = { - doGenerateCode: function (template) { - var templatePath = this.getProperty('template'); - var templateData = this.getProperty('templateData') || this.getProperty('template-data'); - var resourcePath; - var _this = this; - - if (templatePath) { - this.removeProperty('template'); - - var dataExpression; - if (templateData) { - dataExpression = templateData; - } else { - dataExpression = { - toString: function () { - var propParts = []; - - _this.forEachProperty(function (name, value) { - name = name.replace(/-([a-z])/g, function (match, lower) { - return lower.toUpperCase(); - }); - propParts.push(stringify(name) + ': ' + value); - }, _this); - - if (_this.hasChildren()) { - propParts.push(stringify('invokeBody') + ': ' + _this.getBodyContentFunctionExpression(template, false)); - } - - return '{' + propParts.join(', ') + '}'; - } - }; - } - template.include(templatePath, dataExpression); - } else if ((resourcePath = this.getAttribute('resource'))) { - var isStatic = this.getProperty('static') !== false; - if (isStatic) { - resourcePath = nodePath.resolve(template.dirname, resourcePath); - if (!fs.existsSync(resourcePath)) { - this.addError('Resource not found: ' + resourcePath); - return; - } - template.write(stringify(fs.readFileSync(resourcePath, {encoding: 'utf8'}))); - } - } else { - this.addError('"template" or "resource" attribute is required'); - } - } -}; -require('raptor-util').inherit(IncludeNode, require('../../compiler').Node); -module.exports = IncludeNode; \ No newline at end of file diff --git a/taglibs/core/InvokeNode.js b/taglibs/core/InvokeNode.js deleted file mode 100644 index 3fb162b6b..000000000 --- a/taglibs/core/InvokeNode.js +++ /dev/null @@ -1,98 +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. - */ -'use strict'; -var forEach = require('raptor-util').forEach; -function InvokeNode(props) { - InvokeNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -InvokeNode.prototype = { - doGenerateCode: function (template) { - var func = this.getProperty('function'); - var funcDef; - var bodyParam; - var definedFunctions = template.getAttribute('core:definedFunctions'); - if (!func) { - this.addError('"function" attribute is required'); - return; - } - if (func.indexOf('(') === -1) { - funcDef = definedFunctions ? definedFunctions[func] : null; - var argParts = []; - var validParamsLookup = {}; - var params = []; - if (funcDef) { - params = funcDef.params || []; - bodyParam = funcDef.bodyParam; - /* - * Loop over the defined parameters to figure out the names of allowed parameters and add them to a lookup - */ - forEach(params, function (param) { - validParamsLookup[param] = true; - }, this); - } - var bodyArg = null; - if (this.hasChildren()) { - if (!funcDef || !funcDef.bodyParam) { - this.addError('Nested content provided when invoking macro "' + func + '" but defined macro does not support nested content.'); - } else { - bodyArg = this.getBodyContentExpression(template, false); - } - } - /* - * VALIDATION: - * Loop over all of the provided attributes and make sure they are allowed - */ - this.forEachProperty(function (name, value) { - if (name === 'function') { - return; - } - if (!validParamsLookup[name]) { - this.addError('Parameter with name "' + name + '" not supported for function with name "' + func + '". Allowed parameters: ' + params.join(', ')); - } - }, this); - /* - * One more pass to build the argument list - */ - forEach(params, function (param) { - validParamsLookup[param] = true; - if (param === bodyParam) { - argParts.push(bodyArg ? bodyArg : 'undefined'); - } else { - var arg = this.getAttribute(param); - if (arg == null) { - argParts.push('undefined'); - } else { - argParts.push(this.getProperty(param)); - } - } - }, this); - template.write(func + '(' + argParts.join(',') + ')'); - } else { - var funcName = func.substring(0, func.indexOf('(')); - funcDef = definedFunctions ? definedFunctions[funcName] : null; - if (funcDef) { - template.write(func); - } else { - template.statement(func + ';\n'); - } - } - } -}; -require('raptor-util').inherit(InvokeNode, require('../../compiler').Node); -module.exports = InvokeNode; \ No newline at end of file diff --git a/taglibs/core/OtherwiseNode.js b/taglibs/core/OtherwiseNode.js deleted file mode 100644 index f752174d9..000000000 --- a/taglibs/core/OtherwiseNode.js +++ /dev/null @@ -1,34 +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. - */ -'use strict'; -function OtherwiseNode(props) { - OtherwiseNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -OtherwiseNode.prototype = { - doGenerateCode: function (template) { - template.line('else {').indent(function () { - this.generateCodeForChildren(template); - }, this).line('}'); - }, - toString: function () { - return ''; - } -}; -require('raptor-util').inherit(OtherwiseNode, require('../../compiler').Node); -module.exports = OtherwiseNode; \ No newline at end of file diff --git a/taglibs/core/RequireNode.js b/taglibs/core/RequireNode.js deleted file mode 100644 index 9f7228b6a..000000000 --- a/taglibs/core/RequireNode.js +++ /dev/null @@ -1,44 +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. - */ -'use strict'; -var varNameRegExp = /^[A-Za-z_][A-Za-z0-9_]*$/; -function RequireNode(props) { - RequireNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -RequireNode.prototype = { - javaScriptOnly: true, - - doGenerateCode: function (template) { - var module = this.getProperty('module'); - var varName = this.getProperty('var'); - - if (!module) { - this.addError('"module" attribute is required'); - } - if (!varName) { - this.addError('"varName" attribute is required'); - } - - if (module && varName) { - template.addStaticVar(varName, 'require(' + module + ')'); - } - } -}; -require('raptor-util').inherit(RequireNode, require('../../compiler').Node); -module.exports = RequireNode; \ No newline at end of file diff --git a/taglibs/core/ScriptletNode.js b/taglibs/core/ScriptletNode.js deleted file mode 100644 index c9b1c05b7..000000000 --- a/taglibs/core/ScriptletNode.js +++ /dev/null @@ -1,32 +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. - */ -'use strict'; -function ScriptletNode(code) { - ScriptletNode.$super.call(this, 'scriptlet'); - this.code = code; -} -ScriptletNode.prototype = { - doGenerateCode: function (template) { - if (this.code) { - template.code(this.code); - } - }, - toString: function () { - return '{%' + this.code + '%}'; - } -}; -require('raptor-util').inherit(ScriptletNode, require('../../compiler').Node); -module.exports = ScriptletNode; \ No newline at end of file diff --git a/taglibs/core/TagHandlerNode.js b/taglibs/core/TagHandlerNode.js deleted file mode 100644 index 2d49d5729..000000000 --- a/taglibs/core/TagHandlerNode.js +++ /dev/null @@ -1,181 +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. - */ -'use strict'; -var objects = require('raptor-objects'); -var extend = require('raptor-util').extend; -var forEachEntry = require('raptor-util').forEachEntry; -var stringify = require('raptor-json/stringify'); -var Expression = require('../../compiler').Expression; -var raptorModulesResolver = require('raptor-modules/resolver'); - -function addHandlerVar(template, renderer) { - var handlerVars = template._handlerVars || (template._handlerVars = {}); - var handlerVar = handlerVars[renderer]; - if (!handlerVar) { - handlerVars[renderer] = handlerVar = renderer.replace(/[.\-\/]/g, '_').replace(/^[_]+/g, ''); - template.addStaticVar(handlerVar, 'require(' + stringify(renderer) + ')'); - } - return handlerVar; -} -function getPropsStr(props, template) { - var propsArray = []; - if (props) { - template.indent(function () { - forEachEntry(props, function (name, value) { - if (value instanceof Expression) { - - var expressionStr; - template.indent(function () { - expressionStr = value.expression.toString(); - }); - propsArray.push(template.indentStr() + stringify(name) + ': ' + expressionStr); - } else if (typeof value === 'string' || typeof value === 'object') { - propsArray.push(template.indentStr() + stringify(name) + ': ' + stringify(value)); - } else { - propsArray.push(template.indentStr() + stringify(name) + ': ' + value); - } - }); - }); - - - if (propsArray.length) { - return '{\n' + propsArray.join(',\n') + '\n' + template.indentStr() + '}'; - } else { - return '{}'; - } - } else { - return '{}'; - } -} -function TagHandlerNode(tag) { - if (!this.nodeType) { - TagHandlerNode.$super.call(this); - } - this.tag = tag; - this.dynamicAttributes = null; - this.preInvokeCode = []; - this.postInvokeCode = []; - this.inputExpression = null; -} -TagHandlerNode.convertNode = function (node, tag) { - extend(node, TagHandlerNode.prototype); - TagHandlerNode.call(node, tag); -}; -TagHandlerNode.prototype = { - addDynamicAttribute: function (name, value) { - if (!this.dynamicAttributes) { - this.dynamicAttributes = {}; - } - this.dynamicAttributes[name] = value; - }, - setDynamicAttributesProperty: function(name) { - this.dynamicAttributesProperty = name; - }, - addPreInvokeCode: function (code) { - this.preInvokeCode.push(code); - }, - addPostInvokeCode: function (code) { - this.postInvokeCode.push(code); - }, - setInputExpression: function (expression) { - this.inputExpression = expression; - }, - 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, new Expression(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'); - }); - } - } -}; -require('raptor-util').inherit(TagHandlerNode, require('../../compiler').Node); -module.exports = TagHandlerNode; \ No newline at end of file diff --git a/taglibs/core/TemplateNode.js b/taglibs/core/TemplateNode.js deleted file mode 100644 index 72ea4eb9c..000000000 --- a/taglibs/core/TemplateNode.js +++ /dev/null @@ -1,42 +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. - */ -'use strict'; -function TemplateNode(props) { - TemplateNode.$super.call(this, 'template', 'core', 'c'); - if (props) { - this.setProperties(props); - } -} -TemplateNode.prototype = { - doGenerateCode: function (template) { - var params = this.getProperty('params'); - if (params) { - params = params.split(/(?:\s*,\s*)|(?:\s+)/g); - params.forEach(function (param) { - param = param.trim(); - if (param.length) { - template.addVar(param, 'data.' + param); - } - }, this); - } else { - params = null; - } - - this.generateCodeForChildren(template); - } -}; -require('raptor-util').inherit(TemplateNode, require('../../compiler').ElementNode); -module.exports = TemplateNode; \ No newline at end of file diff --git a/taglibs/core/VarNode.js b/taglibs/core/VarNode.js deleted file mode 100644 index 5d7604d93..000000000 --- a/taglibs/core/VarNode.js +++ /dev/null @@ -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. - */ -'use strict'; -var varNameRegExp = /^[A-Za-z_][A-Za-z0-9_]*$/; -function VarNode(props) { - VarNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -VarNode.prototype = { - javaScriptOnly: true, - doGenerateCode: function (template) { - var varName = this.getProperty('name'); - var value = this.getProperty('value') || this.getProperty('string-value'); - if (!varName) { - this.addError('"name" attribute is required'); - } else if (!varNameRegExp.test(varName)) { - this.addError('Invalid variable name of "' + varName + '"'); - varName = null; - } - - var isStatic = this.getProperty('static'); - - if (varName) { - if (isStatic) { - template.addStaticVar(varName, value); - } else { - template.statement('var ' + varName + (value ? '=' + value : '') + ';'); - } - } - } -}; -require('raptor-util').inherit(VarNode, require('../../compiler').Node); -module.exports = VarNode; \ No newline at end of file diff --git a/taglibs/core/WhenNode.js b/taglibs/core/WhenNode.js deleted file mode 100644 index 42b2dbda4..000000000 --- a/taglibs/core/WhenNode.js +++ /dev/null @@ -1,41 +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. - */ -'use strict'; -function WhenNode(props) { - WhenNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -WhenNode.prototype = { - doGenerateCode: function (template) { - var test = this.getProperty('test'); - if (!test) { - this.addError('"test" attribute is required for ' + this.toString() + ' tag.'); - } - var ifCode = 'if (' + test + ')'; - if (!this.firstWhen) { - template.line('else ' + ifCode + ' {'); - } else { - template.statement(ifCode + ' {'); - } - template.indent(function () { - this.generateCodeForChildren(template); - }, this).line('}'); - } -}; -require('raptor-util').inherit(WhenNode, require('../../compiler').Node); -module.exports = WhenNode; \ No newline at end of file diff --git a/taglibs/core/WithNode.js b/taglibs/core/WithNode.js deleted file mode 100644 index c0c770c7d..000000000 --- a/taglibs/core/WithNode.js +++ /dev/null @@ -1,52 +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. - */ -'use strict'; -var AttributeSplitter = require('../../compiler').AttributeSplitter; -var varNameRegExp = /^[A-Za-z_][A-Za-z0-9_]*$/; -function WithNode(props) { - WithNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -WithNode.prototype = { - doGenerateCode: function (template) { - var vars = this.getProperty('vars'); - var _this = this; - if (!vars) { - this.addError('"vars" attribute is required'); - } - var withVars = AttributeSplitter.parse(vars, { '*': { type: 'expression' } }, { - ordered: true, - errorHandler: function (message) { - _this.addError('Invalid variable declarations of "' + vars + '". Error: ' + message); - } - }); - var varDefs = []; - withVars.forEach(function (withVar, i) { - if (!varNameRegExp.test(withVar.name)) { - this.addError('Invalid variable name of "' + withVar.name + '" in "' + vars + '"'); - } - varDefs.push((i > 0 ? template.indentStr(1) + ' ' : '') + withVar.name + (withVar.value ? '=' + withVar.value : '') + (i < withVars.length - 1 ? ',\n' : ';')); - }, this); - template.statement('(function() {').indent(function () { - template.statement('var ' + varDefs.join('')); - this.generateCodeForChildren(template); - }, this).line('}());'); - } -}; -require('raptor-util').inherit(WithNode, require('../../compiler').Node); -module.exports = WithNode; \ No newline at end of file diff --git a/taglibs/core/WriteNode.js b/taglibs/core/WriteNode.js deleted file mode 100644 index 515761478..000000000 --- a/taglibs/core/WriteNode.js +++ /dev/null @@ -1,52 +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. - */ -'use strict'; -var EscapeXmlContext = require('../../compiler/lib/EscapeXmlContext'); -function WriteNode(props) { - WriteNode.$super.call(this, 'write'); - if (props) { - this.setProperties(props); - } -} -WriteNode.prototype = { - doGenerateCode: function (template) { - var expression = this.getExpression(); - var escapeXml; - if (this.hasProperty('escapeXml')) { - escapeXml = this.getProperty('escapeXml') !== false; - } else { - escapeXml = this.getProperty('escape-xml') !== false; - } - if (escapeXml === true) { - if (this.getEscapeXmlContext() === EscapeXmlContext.Attribute) { - expression = template.getStaticHelperFunction('escapeXmlAttr', 'xa') + '(' + expression + ')'; - } else { - expression = template.getStaticHelperFunction('escapeXml', 'x') + '(' + expression + ')'; - } - } - if (expression) { - template.write(expression); - } - }, - getExpression: function () { - return this.getProperty('expression') || this.getProperty('value') || this.getAttribute('expression') || this.getAttribute('value'); - }, - toString: function () { - return ''; - } -}; -require('raptor-util').inherit(WriteNode, require('../../compiler').Node); -module.exports = WriteNode; \ No newline at end of file diff --git a/taglibs/core/raptor-taglib.json b/taglibs/core/raptor-taglib.json deleted file mode 100644 index 0770842bf..000000000 --- a/taglibs/core/raptor-taglib.json +++ /dev/null @@ -1,291 +0,0 @@ -{ - "tags": { - "c-template": { - "attributes": { - "name": { - "allow-expressions": false, - "type": "string" - }, - "params": { - "allow-expressions": false, - "type": "string" - } - }, - "node-class": "./TemplateNode" - }, - "*": { - "attributes": { - "c-space": { - "type": "custom", - "allow-expressions": false - }, - "c-whitespace": { - "type": "custom", - "allow-expressions": false - }, - "c-for": { - "allow-expressions": false, - "type": "string" - }, - "c-for-each": { - "allow-expressions": false, - "type": "string" - }, - "c-if": { - "type": "expression" - }, - "c-else": { - "type": "empty" - }, - "c-else-if": { - "type": "expression" - }, - "c-attrs": { - "type": "expression" - }, - "c-when": { - "type": "expression" - }, - "c-with": { - "type": "custom" - }, - "c-otherwise": { - "type": "empty" - }, - "c-parse-body-text": { - "type": "boolean", - "allow-expressions": false - }, - "c-trim-body-indent": { - "type": "boolean", - "allow-expressions": false - }, - "c-strip": { - "type": "boolean", - "allow-expressions": false - }, - "c-content": { - "type": "expression" - }, - "c-replace": { - "type": "expression" - }, - "c-input": { - "type": "expression" - } - }, - "transformer": { - "path": "./CoreTagTransformer", - "priority": 0 - } - }, - "c-for": { - "node-class": "./ForNode", - "attributes": { - "each": { - "required": false, - "allow-expressions": false, - "type": "string" - }, - "separator": { - "type": "string" - }, - "status-var": { - "type": "identifier", - "allow-expressions": false - }, - "for-loop": { - "type": "boolean", - "allow-expressions": false - }, - "iterator": { - "type": "expression" - } - } - }, - "c-write": { - "node-class": "./WriteNode", - "attributes": { - "value": { - "required": true, - "type": "expression" - }, - "escape-xml": { - "type": "boolean", - "allow-expressions": false - } - } - }, - "c-if": { - "node-class": "./IfNode", - "attributes": { - "test": { - "type": "expression" - } - } - }, - "c-else": { - "node-class": "./ElseNode", - "transformer": { - "path": "./ElseTagTransformer", - "name": "ElseTagTransformer", - "properties": { - "type": "else" - } - } - }, - "c-else-if": { - "attributes": { - "test": { - "type": "expression" - } - }, - "node-class": "./ElseIfNode", - "transformer": { - "path": "./ElseTagTransformer", - "name": "ElseIfTagTransformer", - "properties": { - "type": "else-if" - } - } - }, - "c-invoke": { - "node-class": "./InvokeNode", - "attributes": { - "function": { - "type": "custom", - "allow-expressions": false, - "required": true - }, - "*": { - "type": "string", - "allow-expressions": true - } - } - }, - "c-choose": { - "node-class": "./ChooseNode" - }, - "c-when": { - "node-class": "./WhenNode", - "attributes": { - "test": { - "type": "expression" - } - } - }, - "c-otherwise": { - "node-class": "./OtherwiseNode" - }, - "c-def": { - "node-class": "./DefNode", - "attributes": { - "function": { - "type": "custom", - "allow-expressions": false - }, - "body-param": { - "type": "custom", - "allow-expressions": false - } - } - }, - "c-with": { - "node-class": "./WithNode", - "attributes": { - "vars": { - "type": "custom", - "allow-expressions": false - } - } - }, - "c-include": { - "node-class": "./IncludeNode", - "attributes": { - "template": { - "type": "string" - }, - "template-data": { - "type": "expression" - }, - "resource": { - "type": "string" - }, - "static": { - "type": "boolean", - "allow-expressions": false - }, - "*": { - "type": "string" - } - } - }, - "c-attr": { - "attributes": { - "name": { - "type": "string" - }, - "value": { - "type": "string" - }, - "namespace": { - "type": "string" - }, - "prefix": { - "type": "string" - } - } - }, - "c-var": { - "node-class": "./VarNode", - "attributes": { - "name": { - "type": "custom", - "allow-expressions": false - }, - "value": { - "type": "expression" - }, - "static": { - "type": "boolean" - }, - "string-value": { - "type": "string" - }, - "boolean-value": { - "type": "boolean" - }, - "number-value": { - "type": "number" - } - } - }, - "c-require": { - "node-class": "./RequireNode", - "attributes": { - "module": { - "type": "string" - }, - "var": { - "type": "custom", - "allow-expressions": false - } - } - }, - "c-assign": { - "node-class": "./AssignNode", - "attributes": { - "var": { - "type": "custom", - "allow-expressions": false - }, - "value": { - "type": "expression" - } - } - } - }, - "text-transformer": { - "path": "./CoreTextTransformer" - } -} \ No newline at end of file diff --git a/taglibs/html/CommentTag.js b/taglibs/html/CommentTag.js deleted file mode 100644 index 0ad78e27b..000000000 --- a/taglibs/html/CommentTag.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; -module.exports = { - process: function (input, context) { - context.write(''); - } -}; \ No newline at end of file diff --git a/taglibs/html/DocTypeNode.js b/taglibs/html/DocTypeNode.js deleted file mode 100644 index 4cfbc29c1..000000000 --- a/taglibs/html/DocTypeNode.js +++ /dev/null @@ -1,43 +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. - */ -'use strict'; -var ExpressionParser = require('../../compiler').ExpressionParser; -function DocTypeNode(props) { - DocTypeNode.$super.call(this); - if (props) { - this.setProperties(props); - } -} -DocTypeNode.prototype = { - doGenerateCode: function (template) { - var doctype = this.getAttribute('value') || this.getProperty('value'); - template.text(''); - } -}; -require('raptor-util').inherit(DocTypeNode, require('../../compiler').ElementNode); -module.exports = DocTypeNode; \ No newline at end of file diff --git a/taglibs/html/HtmlTagTransformer.js b/taglibs/html/HtmlTagTransformer.js deleted file mode 100644 index eefb61818..000000000 --- a/taglibs/html/HtmlTagTransformer.js +++ /dev/null @@ -1,53 +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. - */ -'use strict'; -var DocTypeNode = require('./DocTypeNode'); -function HtmlTagTransformer() { -} -HtmlTagTransformer.prototype = { - process: function (node, compiler) { - if (node.isElementNode()) { - var options = compiler.options || {}; - var preserveWhitespace = options.preserveWhitespace || {}; - var allowSelfClosing = options.allowSelfClosing || {}; - var startTagOnly = options.startTagOnly || {}; - var lookupKey = node.namespace ? node.namespace + ':' + node.localName : node.localName; - - if (node.isPreserveWhitespace() == null) { - if (preserveWhitespace[lookupKey] === true) { - node.setPreserveWhitespace(true); - } - } - if (allowSelfClosing[lookupKey] === true) { - node.setAllowSelfClosing(true); - } - if (compiler.options.xhtml !== true && startTagOnly[lookupKey] === true) { - node.setStartTagOnly(true); - } - - if (node.getQName() === 'html' && node.hasAttribute('html-doctype')) { - var doctype = node.getAttribute('html-doctype'); - var docTypeNode = new DocTypeNode({ - value: doctype, - pos: node.getPosition() - }); - node.parentNode.insertBefore(docTypeNode, node); - node.removeAttribute('html-doctype'); - } - } - } -}; -module.exports = HtmlTagTransformer; \ No newline at end of file diff --git a/taglibs/html/raptor-taglib.json b/taglibs/html/raptor-taglib.json deleted file mode 100644 index 9e02292e7..000000000 --- a/taglibs/html/raptor-taglib.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "tags": { - "html-html": { - "attributes": { - "doctype": { - "type": "string" - } - } - }, - "html-doctype": { - "attributes": { - "value": { - "type": "custom" - } - }, - "node-class": "./DocTypeNode" - }, - "*": { - "transformer": "./HtmlTagTransformer" - }, - "html-comment": { - "renderer": "./CommentTag" - } - } -} \ No newline at end of file diff --git a/taglibs/layout/PlaceholderTag.js b/taglibs/layout/PlaceholderTag.js deleted file mode 100644 index 0a8b22e28..000000000 --- a/taglibs/layout/PlaceholderTag.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - render: function (input, context) { - var content = input.content[input.name]; - if (content) { - if (content.value) { - context.write(content.value); - } else if (content.invokeBody) { - content.invokeBody(); - } - } else { - if (input.invokeBody) { - input.invokeBody(); - } - } - } -}; \ No newline at end of file diff --git a/taglibs/layout/PutTag.js b/taglibs/layout/PutTag.js deleted file mode 100644 index aa880a7f7..000000000 --- a/taglibs/layout/PutTag.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - render: function (input, context) { - input._layout.handlePutTag(input); - } -}; \ No newline at end of file diff --git a/taglibs/layout/UseTag.js b/taglibs/layout/UseTag.js deleted file mode 100644 index 0e2ba9a15..000000000 --- a/taglibs/layout/UseTag.js +++ /dev/null @@ -1,14 +0,0 @@ -var extend = require('raptor-util').extend; -var raptorTemplates = require('../../'); -module.exports = { - render: function (input, context) { - var content = {}; - input.invokeBody({ - handlePutTag: function (putTag) { - content[putTag.into] = putTag; - } - }); - var viewModel = extend(input['*'] || {}, { layoutContent: content }); - raptorTemplates.render(input.template, viewModel, context); - } -}; \ No newline at end of file diff --git a/taglibs/layout/layout.rtld b/taglibs/layout/layout.rtld deleted file mode 100644 index 2ae4dfc0c..000000000 --- a/taglibs/layout/layout.rtld +++ /dev/null @@ -1,24 +0,0 @@ - - 1.0 - raptor-templates/layout - layout - http://raptorjs.org/templates/layout - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/taglibs/layout/raptor-taglib.json b/taglibs/layout/raptor-taglib.json deleted file mode 100644 index c82b0f7c5..000000000 --- a/taglibs/layout/raptor-taglib.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "tags": { - "layout-use": { - "renderer": "./UseTag", - "attributes": { - "template": { - "type": "path" - }, - "*": { - "remove-dashes": true, - "type": "string" - } - }, - "var": "_layout" - }, - "layout-put": { - "renderer": "./PutTag", - "attributes": { - "into": { - "type": "string" - }, - "value": { - "type": "string" - } - }, - "import-var": { - "_layout": "_layout" - } - }, - "layout-placeholder": { - "renderer": "./PlaceholderTag", - "attributes": { - "name": { - "type": "string" - } - }, - "import-var": { - "content": "data.layoutContent" - } - } - } -} \ No newline at end of file diff --git a/test/render-rhtml-tests.js b/test/render-rhtml-tests.js index a45f69658..5b6002c9b 100644 --- a/test/render-rhtml-tests.js +++ b/test/render-rhtml-tests.js @@ -15,11 +15,11 @@ function testRender(path, data, done, options) { options = options || {}; var compiledPath = nodePath.join(__dirname, path + '.actual.js'); - var compiler = require('../compiler').createCompiler(inputPath); - var src = fs.readFileSync(inputPath, {encoding: 'utf8'}); + // var compiler = require('../compiler').createCompiler(inputPath); + // var src = fs.readFileSync(inputPath, {encoding: 'utf8'}); - var compiledSrc = compiler.compile(src); - fs.writeFileSync(compiledPath, compiledSrc, {encoding: 'utf8'}); + // var compiledSrc = compiler.compile(src); + // fs.writeFileSync(compiledPath, compiledSrc, {encoding: 'utf8'}); // console.log('\nCompiled (' + inputPath + '):\n---------\n' + compiledSrc); @@ -385,5 +385,9 @@ describe('raptor-templates/rhtml' , function() { }, done); }); + it("should support scanning a directory for tags", function(done) { + testRender("test-project/rhtml-templates/scanned-tags.rhtml", {}, done); + }); + }); diff --git a/test/taglib-lookup-tests.js b/test/taglib-lookup-tests.js deleted file mode 100644 index 8a0e0e041..000000000 --- a/test/taglib-lookup-tests.js +++ /dev/null @@ -1,183 +0,0 @@ -'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); - -describe('raptor-templates/taglib-lookup' , 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 lookup core attributes for top-level template', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project')); - // console.log('LOOKUP: ', Object.keys(lookup.attributes)); - var ifAttr = lookup.getAttribute('div', 'c-if'); - expect(ifAttr != null).to.equal(true); - expect(ifAttr.type).to.equal('expression'); - }); - - it('should lookup core tag for top-level template', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project')); - var ifTag = lookup.getTag('c-if'); - expect(ifTag != null).to.equal(true); - expect(ifTag.name).to.equal('c-if'); - }); - - it('should lookup core template for top-level template', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project')); - // console.log(Object.keys(lookup.tags)); - var templateTag = lookup.getTag('c-template'); - expect(templateTag != null).to.equal(true); - expect(templateTag.name).to.equal('c-template'); - }); - - it('should lookup custom tag for top-level template', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project')); - var tag = lookup.getTag('test-hello'); - // console.log(Object.keys(lookup.tags)); - expect(tag != null).to.equal(true); - expect(tag.name).to.equal('test-hello'); - }); - - it('should lookup custom attributes for top-level template', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project')); - // console.log(Object.keys(lookup.attributes)); - var attr = lookup.getAttribute('test-hello', 'name'); - expect(attr != null).to.equal(true); - expect(attr.type).to.equal('string'); - - var attr2 = lookup.getAttribute('test-hello', 'splat'); - expect(attr2 != null).to.equal(true); - expect(attr2.type).to.equal('number'); - - attr = lookup.getAttribute('test-hello', 'expr'); - expect(attr != null).to.equal(true); - expect(attr.type).to.equal('expression'); - }); - - it('should allow for dynamic attributes', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project')); - // console.log(Object.keys(lookup.attributes)); - var attr = lookup.getAttribute('test-hello', 'DYNAMIC'); - expect(attr != null).to.equal(true); - expect(attr.type).to.equal('number'); - }); - - it('should cache a lookup', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup1 = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project')); - var lookup2 = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project')); - var lookup3 = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project/empty')); - var lookup4 = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project/nested')); - expect(lookup1).to.equal(lookup2); - expect(lookup2).to.equal(lookup3); - expect(lookup1).to.not.equal(lookup4); - }); - - it('should lookup nested tags', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project/nested')); - var tag = lookup.getTag('nested-foo'); - - expect(tag != null).to.equal(true); - expect(tag.name).to.equal('nested-foo'); - }); - - it('should lookup attributes for nested tags', function() { - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project/nested')); - // console.log(Object.keys(lookup.attributes)); - var attr = lookup.getAttribute('nested-foo', 'attr1'); - expect(attr != null).to.equal(true); - expect(attr.type).to.equal('string'); - }); - - it('should lookup tag transformers correctly for un-namespaced tags', function() { - var transformers = []; - - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project/nested')); - - lookup.forEachTagTransformer('div', function(transformer) { - transformers.push(transformer); - }); - - expect(transformers.length).to.equal(2); - }); - - it('should lookup tag transformers correctly for namespaced tag with transformer', function() { - var transformers; - - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup; - // lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project/nested')); - - // transformers = []; - // lookup.forEachTagTransformer('nested-foo', function(transformer) { - // transformers.push(transformer); - // }); - - // expect(transformers.length).to.equal(2); - - lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project/transformers')); - - transformers = []; - lookup.forEachTagTransformer('transform-foo', function(transformer) { - transformers.push(transformer); - }); - - expect(transformers.length).to.equal(3); - expect(transformers[0].path.indexOf('foo')).to.not.equal(-1); - expect(transformers[1].path.indexOf('CoreTagTransformer')).to.not.equal(-1); - expect(transformers[2].path.indexOf('HtmlTagTransformer')).to.not.equal(-1); - - transformers = []; - lookup.forEachTagTransformer('transform-bar', function(transformer) { - transformers.push(transformer); - }); - - expect(transformers.length).to.equal(3); - expect(transformers[0].path.indexOf('CoreTagTransformer')).to.not.equal(-1); - expect(transformers[1].path.indexOf('bar')).to.not.equal(-1); - expect(transformers[2].path.indexOf('HtmlTagTransformer')).to.not.equal(-1); - }); - - it('should lookup tag transformers core tag with custom node', function() { - var transformers = []; - - var taglibLookup = require('../compiler/lib/taglib-lookup'); - var lookup = taglibLookup.buildLookup(nodePath.join(__dirname, 'test-project/nested')); - - lookup.forEachTagTransformer('c-else', function(transformer) { - transformers.push(transformer); - }); - - expect(transformers.length).to.equal(3); - expect(transformers[0].path.indexOf('CoreTagTransformer')).to.not.equal(-1); - expect(transformers[1].path.indexOf('ElseTagTransformer')).to.not.equal(-1); - expect(transformers[2].path.indexOf('HtmlTagTransformer')).to.not.equal(-1); - }); - -}); - diff --git a/test/test-project/raptor-taglib.json b/test/test-project/raptor-taglib.json index 3773bc8ba..d851a1b73 100644 --- a/test/test-project/raptor-taglib.json +++ b/test/test-project/raptor-taglib.json @@ -76,5 +76,6 @@ } } } - } + }, + "tags-dir": "./scanned-tags" } \ No newline at end of file diff --git a/test/test-project/rhtml-templates/scanned-tags.rhtml b/test/test-project/rhtml-templates/scanned-tags.rhtml new file mode 100644 index 000000000..ef2f149db --- /dev/null +++ b/test/test-project/rhtml-templates/scanned-tags.rhtml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/test/test-project/rhtml-templates/scanned-tags.rhtml.expected.html b/test/test-project/rhtml-templates/scanned-tags.rhtml.expected.html new file mode 100644 index 000000000..db1ab152f --- /dev/null +++ b/test/test-project/rhtml-templates/scanned-tags.rhtml.expected.html @@ -0,0 +1 @@ +scanned-a: Hello Frankscanned-b: Hello Frankscanned-c: Hello Frankscanned-d: Hello Frankscanned-e: Hello Frankscanned-f: Hello Frank \ No newline at end of file diff --git a/test/test-project/scanned-tags/scanned-a/renderer.js b/test/test-project/scanned-tags/scanned-a/renderer.js new file mode 100644 index 000000000..06a4d4d5e --- /dev/null +++ b/test/test-project/scanned-tags/scanned-a/renderer.js @@ -0,0 +1,3 @@ +module.exports = function render(input, context) { + context.write('scanned-a: Hello ' + input.name); +}; \ No newline at end of file diff --git a/test/test-project/scanned-tags/scanned-b/template.rhtml b/test/test-project/scanned-tags/scanned-b/template.rhtml new file mode 100644 index 000000000..44a949161 --- /dev/null +++ b/test/test-project/scanned-tags/scanned-b/template.rhtml @@ -0,0 +1 @@ +scanned-b: Hello ${data.name} \ No newline at end of file diff --git a/test/test-project/scanned-tags/scanned-c/raptor-tag.json b/test/test-project/scanned-tags/scanned-c/raptor-tag.json new file mode 100644 index 000000000..c3d3b15c3 --- /dev/null +++ b/test/test-project/scanned-tags/scanned-c/raptor-tag.json @@ -0,0 +1,8 @@ +{ + "attributes": { + "name": { + "type": "string", + "target-property": "NAME" + } + } +} \ No newline at end of file diff --git a/test/test-project/scanned-tags/scanned-c/renderer.js b/test/test-project/scanned-tags/scanned-c/renderer.js new file mode 100644 index 000000000..f844ff84a --- /dev/null +++ b/test/test-project/scanned-tags/scanned-c/renderer.js @@ -0,0 +1,3 @@ +module.exports = function render(input, context) { + context.write('scanned-c: Hello ' + input.NAME); +}; \ No newline at end of file diff --git a/test/test-project/scanned-tags/scanned-d/template.rhtml b/test/test-project/scanned-tags/scanned-d/template.rhtml new file mode 100644 index 000000000..27f01b37d --- /dev/null +++ b/test/test-project/scanned-tags/scanned-d/template.rhtml @@ -0,0 +1,11 @@ + +scanned-d: Hello ${data.NAME} \ No newline at end of file diff --git a/test/test-project/scanned-tags/scanned-e/renderer.js b/test/test-project/scanned-tags/scanned-e/renderer.js new file mode 100644 index 000000000..fc86a4990 --- /dev/null +++ b/test/test-project/scanned-tags/scanned-e/renderer.js @@ -0,0 +1,12 @@ +exports.TAG = { + "attributes": { + "name": { + "type": "string", + "target-property": "NAME" + } + } +}; + +module.exports = function render(input, context) { + context.write('scanned-e: Hello ' + input.NAME); +}; \ No newline at end of file diff --git a/test/test-project/scanned-tags/scanned-f/renderer.js b/test/test-project/scanned-tags/scanned-f/renderer.js new file mode 100644 index 000000000..ccddb5b28 --- /dev/null +++ b/test/test-project/scanned-tags/scanned-f/renderer.js @@ -0,0 +1,14 @@ +/* +TAG = { + "attributes": { + "name": { + "type": "string", + "target-property": "NAME" + } + } +} +*/ + +module.exports = function render(input, context) { + context.write('scanned-f: Hello ' + input.NAME); +}; \ No newline at end of file