mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Expose method for creating an AST node from an HTML element
This commit is contained in:
parent
fb6b436063
commit
2a34d940e4
@ -8,6 +8,16 @@ var deresolve = require('./util/deresolve');
|
|||||||
var UniqueVars = require('./util/UniqueVars');
|
var UniqueVars = require('./util/UniqueVars');
|
||||||
var PosInfo = require('./util/PosInfo');
|
var PosInfo = require('./util/PosInfo');
|
||||||
var CompileError = require('./CompileError');
|
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 {
|
class CompileContext {
|
||||||
constructor(src, filename, builder) {
|
constructor(src, filename, builder) {
|
||||||
@ -73,6 +83,101 @@ class CompileContext {
|
|||||||
getStaticVars() {
|
getStaticVars() {
|
||||||
return this._staticVars;
|
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;
|
module.exports = CompileContext;
|
||||||
@ -1,7 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
var ok = require('assert').ok;
|
var ok = require('assert').ok;
|
||||||
var path = require('path');
|
|
||||||
var Node = require('./ast/Node');
|
|
||||||
|
|
||||||
var COMPILER_ATTRIBUTE_HANDLERS = {
|
var COMPILER_ATTRIBUTE_HANDLERS = {
|
||||||
whitespace: function(attr, compilerOptions) {
|
whitespace: function(attr, compilerOptions) {
|
||||||
@ -27,15 +25,6 @@ function parseExpression(expression) {
|
|||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTaglibPath(taglibPath) {
|
|
||||||
if (typeof window === 'undefined') {
|
|
||||||
return path.relative(process.cwd(), taglibPath);
|
|
||||||
} else {
|
|
||||||
return taglibPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Parser {
|
class Parser {
|
||||||
constructor(parserImpl) {
|
constructor(parserImpl) {
|
||||||
ok(parserImpl, '"parserImpl" is required');
|
ok(parserImpl, '"parserImpl" is required');
|
||||||
@ -118,11 +107,10 @@ class Parser {
|
|||||||
|
|
||||||
this.prevTextNode = null;
|
this.prevTextNode = null;
|
||||||
|
|
||||||
var node;
|
|
||||||
|
|
||||||
var elDef = {
|
var elDef = {
|
||||||
tagName: tagName,
|
tagName: tagName,
|
||||||
argument: argument,
|
argument: argument,
|
||||||
|
pos: el.pos,
|
||||||
attributes: attributes.map((attr) => {
|
attributes: attributes.map((attr) => {
|
||||||
var isLiteral = false;
|
var isLiteral = false;
|
||||||
|
|
||||||
@ -145,73 +133,7 @@ class Parser {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
var elNode = builder.htmlElement(elDef);
|
var node = this.context.createNodeForEl(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) + '".'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.parentNode.appendChild(node);
|
this.parentNode.appendChild(node);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user