'use strict'; var ok = require('assert').ok; var replacePlaceholderEscapeFuncs = require('./util/replacePlaceholderEscapeFuncs'); var COMPILER_ATTRIBUTE_HANDLERS = { 'preserve-whitespace': function(attr, context) { context.setPreserveWhitespace(true); }, 'preserve-comments': function(attr, context) { context.setPreserveComments(true); } }; var ieConditionalCommentRegExp = /^\[if [^]*? { return builder.parseExpression(className.value); }); var classAttr = el.getAttributeValue('class'); if (classAttr) { classNames.push(classAttr); } let prevClassName; var finalClassNames = []; for (var i=0; i, argument will be "color in colors" if (argument) { argument = argument.value; } var raw = this.raw; if (!raw) { if (tagNameExpression) { tagName = builder.parseExpression(tagNameExpression); } else if (tagName === 'marko-compiler-options') { this.parentNode.setTrimStartEnd(true); attributes.forEach(function (attr) { let attrName = attr.name; let handler = COMPILER_ATTRIBUTE_HANDLERS[attrName]; if (!handler) { context.addError({ code: 'ERR_INVALID_COMPILER_OPTION', message: 'Invalid Marko compiler option of "' + attrName + '". Allowed: ' + Object.keys(COMPILER_ATTRIBUTE_HANDLERS).join(', '), pos: el.pos, node: el }); return; } handler(attr, context); }); return; } } this.prevTextNode = null; var attributeParseErrors = []; var elDef = { tagName: tagName, argument: argument, openTagOnly: el.openTagOnly === true, selfClosed: el.selfClosed === true, pos: el.pos, attributes: attributes.map((attr) => { var attrValue; if (attr.hasOwnProperty('literalValue')) { attrValue = builder.literal(attr.literalValue); } else if (attr.value == null) { attrValue = undefined; } else { let parsedExpression; let valid = true; try { parsedExpression = builder.parseExpression(attr.value); } catch(e) { valid = false; attributeParseErrors.push('Invalid JavaScript expression for attribute "' + attr.name + '": ' + e); } if (valid) { if (raw) { attrValue = parsedExpression; } else { attrValue = replacePlaceholderEscapeFuncs(parsedExpression, context); } } else { attrValue = null; } } var attrDef = { name: attr.name, value: attrValue, rawValue: attr.value }; if (attr.argument) { // TODO Do something with the argument pos attrDef.argument = attr.argument.value; } return attrDef; }) }; var node; if (raw) { node = builder.htmlElement(elDef); node.pos = elDef.pos; let taglibLookup = this.context.taglibLookup; let tagDef = taglibLookup.getTag(tagName); node.tagDef = tagDef; } else { node = this.context.createNodeForEl(elDef); } if (attributeParseErrors.length) { attributeParseErrors.forEach((e) => { context.addError(node, e); }); } if (raw) { if (el.shorthandId) { let parsed = builder.parseExpression(el.shorthandId.value); node.rawShorthandId = parsed.value; } if (el.shorthandClassNames) { node.rawShorthandClassNames = el.shorthandClassNames.map((className) => { let parsed = builder.parseExpression(className.value); return parsed.value; }); } } else { if (el.shorthandClassNames) { mergeShorthandClassNames(node, el.shorthandClassNames, context); } if (el.shorthandId) { if (node.hasAttribute('id')) { context.addError(node, 'A shorthand ID cannot be used in conjunction with the "id" attribute'); } else { node.setAttributeValue('id', builder.parseExpression(el.shorthandId.value)); } } } this.parentNode.appendChild(node); this.stack.push({ node: node, tag: null }); } handleEndElement(elementName) { if (this.raw !== true) { if (elementName === 'marko-compiler-options') { return; } } this.prevTextNode = null; this.stack.pop(); } handleComment(comment) { this.prevTextNode = null; var builder = this.context.builder; var preserveComment = this.context.isPreserveComments() || isIEConditionalComment(comment); if (this.raw || preserveComment) { var commentNode = builder.htmlComment(builder.literal(comment)); this.parentNode.appendChild(commentNode); } } handleDeclaration(value) { this.prevTextNode = null; var builder = this.context.builder; var declarationNode = builder.declaration(builder.literal(value)); this.parentNode.appendChild(declarationNode); } handleDocumentType(value) { this.prevTextNode = null; var builder = this.context.builder; var docTypeNode = builder.documentType(builder.literal(value)); this.parentNode.appendChild(docTypeNode); } handleBodyTextPlaceholder(expression, escape) { this.prevTextNode = null; var builder = this.context.builder; var parsedExpression = builder.parseExpression(expression); var preserveWhitespace = true; var text = builder.text(parsedExpression, escape, preserveWhitespace); this.parentNode.appendChild(text); } handleScriptlet(code) { this.prevTextNode = null; var builder = this.context.builder; var scriptlet = builder.scriptlet(code); this.parentNode.appendChild(scriptlet); } handleError(event) { this.context.addError({ message: event.message, code: event.code, pos: event.pos, endPos: event.endPos }); } get parentNode() { var last = this.stack[this.stack.length-1]; return last.node; } getParserStateForTag(el) { var attributes = el.attributes; for (var i=0; i