diff --git a/compiler/CompileContext.js b/compiler/CompileContext.js index 59f84794d..befcf940a 100644 --- a/compiler/CompileContext.js +++ b/compiler/CompileContext.js @@ -8,6 +8,16 @@ var deresolve = require('./util/deresolve'); var UniqueVars = require('./util/UniqueVars'); var PosInfo = require('./util/PosInfo'); var CompileError = require('./CompileError'); +var path = require('path'); +var Node = require('./ast/Node'); + +function getTaglibPath(taglibPath) { + if (typeof window === 'undefined') { + return path.relative(process.cwd(), taglibPath); + } else { + return taglibPath; + } +} class CompileContext { constructor(src, filename, builder) { @@ -73,6 +83,101 @@ class CompileContext { getStaticVars() { return this._staticVars; } + + createNodeForEl(tagName, attributes, argument) { + var elDef; + var builder = this.builder; + + if (typeof tagName === 'object') { + elDef = tagName; + tagName = elDef.tagName; + attributes = elDef.attributes; + argument = elDef.argument; + } else { + elDef = { + tagName: tagName, + argument: argument, + attributes: attributes + }; + } + + ok(typeof tagName === 'string', 'Invalid "tagName"'); + ok(attributes == null || Array.isArray(attributes), 'Invalid "attributes"'); + + if (!attributes) { + attributes = elDef.attributes = []; + } + + var node; + var elNode = builder.htmlElement(elDef); + var taglibLookup = this.taglibLookup; + var tagDef = taglibLookup.getTag(tagName); + if (tagDef) { + var nodeFactoryFunc = tagDef.getNodeFactory(); + if (nodeFactoryFunc) { + node = nodeFactoryFunc(elNode, this); + if (!(node instanceof Node)) { + throw new Error('Invalid node returned from node factory for tag "' + tagName + '".'); + } + } + } + + if (!node) { + node = elNode; + } + + node.pos = elDef.pos; + + var foundAttrs = {}; + + // Validate the attributes + attributes.forEach((attr) => { + let attrName = attr.name; + let attrDef = taglibLookup.getAttribute(tagName, attrName); + if (!attrDef) { + if (tagDef) { + // var isAttrForTaglib = compiler.taglibs.isTaglib(attrUri); + //Tag doesn't allow dynamic attributes + this.addError({ + node: node, + message: 'The tag "' + tagName + '" in taglib "' + getTaglibPath(tagDef.taglibId) + '" does not support attribute "' + attrName + '"' + }); + + } + return; + } + + attr.def = attrDef; + + foundAttrs[attrName] = true; + }); + + if (tagDef) { + // Add default values for any attributes. If an attribute has a declared + // default value and the attribute was not found on the element + // then add the attribute with the specified default value + tagDef.forEachAttribute((attrDef) => { + var attrName = attrDef.name; + + if (attrDef.hasOwnProperty('defaultValue') && !foundAttrs.hasOwnProperty(attrName)) { + attributes.push({ + name: attrName, + value: builder.literal(attrDef.defaultValue) + }); + } else if (attrDef.required === true) { + // TODO Only throw an error if there is no data argument provided (just HTML attributes) + if (!foundAttrs.hasOwnProperty(attrName)) { + this.addError({ + node: node, + message: 'The "' + attrName + '" attribute is required for tag "' + tagName + '" in taglib "' + getTaglibPath(tagDef.taglibId) + '".' + }); + } + } + }); + } + + return node; + } } module.exports = CompileContext; \ No newline at end of file diff --git a/compiler/Parser.js b/compiler/Parser.js index 310120fa5..5254820cf 100644 --- a/compiler/Parser.js +++ b/compiler/Parser.js @@ -1,7 +1,5 @@ 'use strict'; var ok = require('assert').ok; -var path = require('path'); -var Node = require('./ast/Node'); var COMPILER_ATTRIBUTE_HANDLERS = { whitespace: function(attr, compilerOptions) { @@ -27,15 +25,6 @@ function parseExpression(expression) { return expression; } -function getTaglibPath(taglibPath) { - if (typeof window === 'undefined') { - return path.relative(process.cwd(), taglibPath); - } else { - return taglibPath; - } -} - - class Parser { constructor(parserImpl) { ok(parserImpl, '"parserImpl" is required'); @@ -118,11 +107,10 @@ class Parser { this.prevTextNode = null; - var node; - var elDef = { tagName: tagName, argument: argument, + pos: el.pos, attributes: attributes.map((attr) => { var isLiteral = false; @@ -145,73 +133,7 @@ class Parser { }) }; - var elNode = builder.htmlElement(elDef); - - var taglibLookup = context.taglibLookup; - var tagDef = taglibLookup.getTag(tagName); - if (tagDef) { - var nodeFactoryFunc = tagDef.getNodeFactory(); - if (nodeFactoryFunc) { - node = nodeFactoryFunc(elNode, context); - if (!(node instanceof Node)) { - throw new Error('Invalid node returned from node factory for tag "' + tagName + '".'); - } - } - } - - if (!node) { - node = elNode; - } - - node.pos = el.pos; - - var foundAttrs = {}; - - // Validate the attributes - attributes.forEach((attr) => { - let attrName = attr.name; - let attrDef = taglibLookup.getAttribute(tagName, attrName); - if (!attrDef) { - if (tagDef) { - // var isAttrForTaglib = compiler.taglibs.isTaglib(attrUri); - //Tag doesn't allow dynamic attributes - context.addError({ - node: node, - message: 'The tag "' + tagName + '" in taglib "' + getTaglibPath(tagDef.taglibId) + '" does not support attribute "' + attrName + '"' - }); - - } - return; - } - - attr.def = attrDef; - - foundAttrs[attrName] = true; - }); - - if (tagDef) { - // Add default values for any attributes. If an attribute has a declared - // default value and the attribute was not found on the element - // then add the attribute with the specified default value - tagDef.forEachAttribute(function (attrDef) { - var attrName = attrDef.name; - - if (attrDef.hasOwnProperty('defaultValue') && !foundAttrs.hasOwnProperty(attrName)) { - attributes.push({ - name: attrName, - value: builder.literal(attrDef.defaultValue) - }); - } else if (attrDef.required === true) { - // TODO Only throw an error if there is no data argument provided (just HTML attributes) - if (!foundAttrs.hasOwnProperty(attrName)) { - context.addError({ - node: node, - message: 'The "' + attrName + '" attribute is required for tag "' + tagName + '" in taglib "' + getTaglibPath(tagDef.taglibId) + '".' - }); - } - } - }); - } + var node = this.context.createNodeForEl(elDef); this.parentNode.appendChild(node);