mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Added support for parsing a template to get the "raw" AST (no resolving custom tags, custom attributes, placeholders, etc.)
This commit is contained in:
parent
579ef6310f
commit
bd51b39ce0
@ -2,6 +2,10 @@
|
||||
var htmljs = require('htmljs-parser');
|
||||
|
||||
class HtmlJsParser {
|
||||
constructor(options) {
|
||||
this.ignorePlaceholders = options && options.ignorePlaceholders === true;
|
||||
}
|
||||
|
||||
parse(src, handlers) {
|
||||
var listeners = {
|
||||
onText(event) {
|
||||
@ -54,12 +58,11 @@ class HtmlJsParser {
|
||||
|
||||
// Document type: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
|
||||
// NOTE: The value will be all of the text between "<!" and ">""
|
||||
handlers.handleCharacters('<!' + event.value + '>');
|
||||
handlers.handleDocumentType(event.value);
|
||||
},
|
||||
|
||||
onDeclaration(event) {
|
||||
// Declaration (e.g. <?xml version="1.0" encoding="UTF-8" ?>)
|
||||
handlers.handleCharacters('<?' + event.value + '?>');
|
||||
handlers.handleDeclaration(event.value);
|
||||
},
|
||||
|
||||
onComment(event) {
|
||||
@ -78,6 +81,7 @@ class HtmlJsParser {
|
||||
};
|
||||
|
||||
var parser = this.parser = htmljs.createParser(listeners, {
|
||||
ignorePlaceholders: this.ignorePlaceholders,
|
||||
isOpenTagOnly: function(tagName) {
|
||||
return handlers.isOpenTagOnly(tagName);
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ function mergeShorthandClassNames(el, shorthandClassNames, context) {
|
||||
}
|
||||
|
||||
class Parser {
|
||||
constructor(parserImpl) {
|
||||
constructor(parserImpl, options) {
|
||||
ok(parserImpl, '"parserImpl" is required');
|
||||
|
||||
this.parserImpl = parserImpl;
|
||||
@ -77,6 +77,8 @@ class Parser {
|
||||
this.prevTextNode = null;
|
||||
this.stack = null;
|
||||
|
||||
this.raw = options && options.raw === true;
|
||||
|
||||
// The context gets provided when parse is called
|
||||
// but we store it as part of the object so that the handler
|
||||
// methods have access
|
||||
@ -133,27 +135,31 @@ class Parser {
|
||||
argument = argument.value;
|
||||
}
|
||||
|
||||
if (tagNameExpression) {
|
||||
tagName = builder.parseExpression(tagNameExpression);
|
||||
} else if (tagName === 'marko-compiler-options') {
|
||||
attributes.forEach(function (attr) {
|
||||
let attrName = attr.name;
|
||||
let handler = COMPILER_ATTRIBUTE_HANDLERS[attrName];
|
||||
var raw = this.raw;
|
||||
|
||||
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;
|
||||
}
|
||||
if (!raw) {
|
||||
if (tagNameExpression) {
|
||||
tagName = builder.parseExpression(tagNameExpression);
|
||||
} else if (tagName === 'marko-compiler-options') {
|
||||
attributes.forEach(function (attr) {
|
||||
let attrName = attr.name;
|
||||
let handler = COMPILER_ATTRIBUTE_HANDLERS[attrName];
|
||||
|
||||
handler(attr, context);
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
||||
return;
|
||||
handler(attr, context);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.prevTextNode = null;
|
||||
@ -183,11 +189,14 @@ class Parser {
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
attrValue = replacePlaceholderEscapeFuncs(parsedExpression, context);
|
||||
if (raw) {
|
||||
attrValue = parsedExpression;
|
||||
} else {
|
||||
attrValue = replacePlaceholderEscapeFuncs(parsedExpression, context);
|
||||
}
|
||||
} else {
|
||||
attrValue = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var attrDef = {
|
||||
@ -205,7 +214,14 @@ class Parser {
|
||||
})
|
||||
};
|
||||
|
||||
var node = this.context.createNodeForEl(elDef);
|
||||
var node;
|
||||
|
||||
if (raw) {
|
||||
node = builder.htmlElement(elDef);
|
||||
node.pos = elDef.pos;
|
||||
} else {
|
||||
node = this.context.createNodeForEl(elDef);
|
||||
}
|
||||
|
||||
if (attributeParseErrors.length) {
|
||||
|
||||
@ -214,15 +230,31 @@ class Parser {
|
||||
});
|
||||
}
|
||||
|
||||
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));
|
||||
// TODO Retain the shorthand class names and IDs in raw mode
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,12 +284,30 @@ class Parser {
|
||||
var preserveComment = this.context.isPreserveComments() ||
|
||||
isIEConditionalComment(comment);
|
||||
|
||||
if (preserveComment) {
|
||||
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;
|
||||
|
||||
@ -6,8 +6,16 @@ var Parser = require('./Parser');
|
||||
var HtmlJsParser = require('./HtmlJsParser');
|
||||
var Builder = require('./Builder');
|
||||
var extend = require('raptor-util/extend');
|
||||
var CompileContext = require('./CompileContext');
|
||||
var NODE_ENV = process.env.NODE_ENV;
|
||||
var defaultParser = new Parser(new HtmlJsParser());
|
||||
var rawParser = new Parser(
|
||||
new HtmlJsParser({
|
||||
ignorePlaceholders: true
|
||||
}),
|
||||
{
|
||||
raw: true
|
||||
});
|
||||
|
||||
var defaultOptions = {
|
||||
/**
|
||||
@ -133,9 +141,15 @@ function clearCaches() {
|
||||
exports.taglibLoader.clearCache();
|
||||
}
|
||||
|
||||
function parseRaw(templateSrc, filename) {
|
||||
var context = new CompileContext(templateSrc, filename, Builder.DEFAULT_BUILDER);
|
||||
return rawParser.parse(templateSrc, context);
|
||||
}
|
||||
|
||||
exports.createBuilder = createBuilder;
|
||||
exports.compileFile = compileFile;
|
||||
exports.compile = compile;
|
||||
exports.parseRaw = parseRaw;
|
||||
exports.defaultOptions = defaultOptions;
|
||||
exports.checkUpToDate = checkUpToDate;
|
||||
exports.getLastModified = getLastModified;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user