mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Reintroduced attrs support
This commit is contained in:
parent
a4dee1bbf3
commit
66f9be0d4e
@ -91,6 +91,7 @@ class Generator {
|
|||||||
throw new Error('Root node is not of type "TemplateRoot". Actual ' + JSON.stringify(templateRoot));
|
throw new Error('Root node is not of type "TemplateRoot". Actual ' + JSON.stringify(templateRoot));
|
||||||
}
|
}
|
||||||
templateRoot.addStaticVar(name, value);
|
templateRoot.addStaticVar(name, value);
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
generateCode(node, options) {
|
generateCode(node, options) {
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class ArrayContainer extends Container {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
forEach(callback, thisObj) {
|
forEach(callback, thisObj) {
|
||||||
var array = this.array;
|
var array = this.array.concat([]);
|
||||||
for (var i=0; i<array.length; i++) {
|
for (var i=0; i<array.length; i++) {
|
||||||
var item = array[i];
|
var item = array[i];
|
||||||
if (item.container === this) {
|
if (item.container === this) {
|
||||||
|
|||||||
17
compiler/ast/CustomTag.js
Normal file
17
compiler/ast/CustomTag.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var HtmlElement = require('./HtmlElement');
|
||||||
|
|
||||||
|
class CustomTag extends HtmlElement {
|
||||||
|
constructor(def) {
|
||||||
|
super('Identifier');
|
||||||
|
this.name = def.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateCode(generator) {
|
||||||
|
var name = this.name;
|
||||||
|
generator.write(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Identifier;
|
||||||
@ -17,6 +17,7 @@ class HtmlElement extends Node {
|
|||||||
this.argument = def.argument;
|
this.argument = def.argument;
|
||||||
this.allowSelfClosing = false;
|
this.allowSelfClosing = false;
|
||||||
this.startTagOnly = false;
|
this.startTagOnly = false;
|
||||||
|
this._dynamicAttributesExpressionArray = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
generateHtmlCode(generator) {
|
generateHtmlCode(generator) {
|
||||||
@ -25,6 +26,7 @@ class HtmlElement extends Node {
|
|||||||
var startTagOnly = this.startTagOnly;
|
var startTagOnly = this.startTagOnly;
|
||||||
var allowSelfClosing = this.allowSelfClosing;
|
var allowSelfClosing = this.allowSelfClosing;
|
||||||
var hasBody = body && body.length;
|
var hasBody = body && body.length;
|
||||||
|
var builder = generator.builder;
|
||||||
|
|
||||||
// Starting tag
|
// Starting tag
|
||||||
generator.addWriteLiteral('<' + tagName);
|
generator.addWriteLiteral('<' + tagName);
|
||||||
@ -63,6 +65,14 @@ class HtmlElement extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._dynamicAttributesExpressionArray) {
|
||||||
|
this._dynamicAttributesExpressionArray.forEach(function(attrsExpression) {
|
||||||
|
generator.addStaticVar('attrs', '__helpers.as');
|
||||||
|
let attrsFunctionCall = builder.functionCall('attrs', [attrsExpression]);
|
||||||
|
generator.addWrite(attrsFunctionCall);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (hasBody) {
|
if (hasBody) {
|
||||||
generator.addWriteLiteral('>');
|
generator.addWriteLiteral('>');
|
||||||
} else {
|
} else {
|
||||||
@ -94,6 +104,14 @@ class HtmlElement extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addDynamicAttributes(expression) {
|
||||||
|
if (!this._dynamicAttributesExpressionArray) {
|
||||||
|
this._dynamicAttributesExpressionArray = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dynamicAttributesExpressionArray.push(expression);
|
||||||
|
}
|
||||||
|
|
||||||
removeAttribute(name) {
|
removeAttribute(name) {
|
||||||
if (this._attributes) {
|
if (this._attributes) {
|
||||||
this._attributes.removeAttribute(name);
|
this._attributes.removeAttribute(name);
|
||||||
@ -111,6 +129,14 @@ class HtmlElement extends Node {
|
|||||||
get attributes() {
|
get attributes() {
|
||||||
return this._attributes.all;
|
return this._attributes.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forEachAttribute(callback, thisObj) {
|
||||||
|
var attributes = this._attributes.all.concat([]);
|
||||||
|
|
||||||
|
for (let i=0, len=attributes.length; i<len; i++) {
|
||||||
|
callback.call(thisObj, attributes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = HtmlElement;
|
module.exports = HtmlElement;
|
||||||
@ -94,6 +94,15 @@ var coreAttrHandlers = [
|
|||||||
|
|
||||||
el.setStripExpression(attr);
|
el.setStripExpression(attr);
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'attrs', function(attr, node) {
|
||||||
|
if (!node.addDynamicAttributes) {
|
||||||
|
node.addError('Node does not support the "attrs" attribute');
|
||||||
|
} else {
|
||||||
|
node.addDynamicAttributes(attr.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -139,20 +148,16 @@ var attributeTransformers = AttributeTransformer.prototype;
|
|||||||
module.exports = function transform(el, compiler) {
|
module.exports = function transform(el, compiler) {
|
||||||
var attributeTransfomer;
|
var attributeTransfomer;
|
||||||
|
|
||||||
var attributes = el.getAttributes();
|
el.forEachAttribute((attr) => {
|
||||||
if (attributes) {
|
let attrName = attr.name;
|
||||||
for (let i=0, len=attributes.length; i<len; i++) {
|
var attrTransformerFunc = attributeTransformers[attrName];
|
||||||
let attr = attributes[i];
|
if (attrTransformerFunc) {
|
||||||
let attrName = attr.name;
|
el.removeAttribute(attrName);
|
||||||
var attrTransformerFunc = attributeTransformers[attrName];
|
|
||||||
if (attrTransformerFunc) {
|
|
||||||
el.removeAttribute(attrName);
|
|
||||||
|
|
||||||
if (!attributeTransfomer) {
|
if (!attributeTransfomer) {
|
||||||
attributeTransfomer = new AttributeTransformer(compiler, el);
|
attributeTransfomer = new AttributeTransformer(compiler, el);
|
||||||
}
|
|
||||||
attributeTransfomer[attrName](attr, el);
|
|
||||||
}
|
}
|
||||||
|
attributeTransfomer[attrName](attr, el);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
@ -1,30 +1,47 @@
|
|||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var enabledTest = process.env.TEST;
|
var enabledTest = process.env.TEST;
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
function autoTest(name, dir, run, options) {
|
function autoTest(name, dir, run, options) {
|
||||||
var compareExtension = (options && options.compareExtension) || '.js';
|
var compareExtension = (options && options.compareExtension) || '.js';
|
||||||
|
var isJSON = compareExtension === '.json';
|
||||||
|
|
||||||
var actualPath = path.join(dir, 'actual' + compareExtension);
|
var actualPath = path.join(dir, 'actual' + compareExtension);
|
||||||
var expectedPath = path.join(dir, 'expected' + compareExtension);
|
var expectedPath = path.join(dir, 'expected' + compareExtension);
|
||||||
|
|
||||||
var actual = run(dir);
|
var actual = run(dir);
|
||||||
|
var actualJSON = isJSON ? JSON.stringify(actual, null, 2) : null;
|
||||||
|
|
||||||
fs.writeFileSync(actualPath, actual, {encoding: 'utf8'});
|
fs.writeFileSync(
|
||||||
|
actualPath,
|
||||||
|
isJSON ? actualJSON : actual,
|
||||||
|
{encoding: 'utf8'});
|
||||||
|
|
||||||
var expected;
|
var expected;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
expected = fs.readFileSync(expectedPath, { encoding: 'utf8' });
|
expected = fs.readFileSync(expectedPath, { encoding: 'utf8' });
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
expected = 'TBD';
|
expected = isJSON ? '"TBD"' : 'TBD';
|
||||||
fs.writeFileSync(expectedPath, expected, {encoding: 'utf8'});
|
fs.writeFileSync(expectedPath, expected, {encoding: 'utf8'});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actual !== expected) {
|
var expectedJSON;
|
||||||
throw new Error('Unexpected output for "' + name + '":\nEXPECTED (' + expectedPath + '):\n---------\n' + expected +
|
|
||||||
'\n---------\nACTUAL (' + actualPath + '):\n---------\n' + actual + '\n---------');
|
if (isJSON) {
|
||||||
|
expectedJSON = expected;
|
||||||
|
expected = JSON.parse(expectedJSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
(isJSON ? JSON.parse(actualJSON) : actual),
|
||||||
|
expected,
|
||||||
|
'Unexpected output for "' + name + '":\nEXPECTED (' + expectedPath + '):\n---------\n' +
|
||||||
|
(isJSON ? expectedJSON : expected) +
|
||||||
|
'\n---------\nACTUAL (' + actualPath + '):\n---------\n' +
|
||||||
|
(isJSON ? actualJSON : actual) +
|
||||||
|
'\n---------');
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.scanDir = function(autoTestDir, run, options) {
|
exports.scanDir = function(autoTestDir, run, options) {
|
||||||
|
|||||||
@ -1 +1,42 @@
|
|||||||
TBD
|
function create(__helpers) {
|
||||||
|
var str = __helpers.s,
|
||||||
|
empty = __helpers.e,
|
||||||
|
notEmpty = __helpers.ne,
|
||||||
|
escapeXml = __helpers.x,
|
||||||
|
forEach = __helpers.f;
|
||||||
|
|
||||||
|
return function render(data, out) {
|
||||||
|
out.w("Hello ! " +
|
||||||
|
escapeXml(data.name));
|
||||||
|
|
||||||
|
if (notEmpty(data.colors)) {
|
||||||
|
out.w("<ul>");
|
||||||
|
|
||||||
|
forEach(data.colors, function(color) {
|
||||||
|
out.w("<li>" +
|
||||||
|
escapeXml(color) +
|
||||||
|
"</li>");
|
||||||
|
});
|
||||||
|
|
||||||
|
out.w("</ul>");
|
||||||
|
} else {
|
||||||
|
out.w("<div>No colors!</div>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notEmpty(data.colors)) {
|
||||||
|
out.w("<ul>");
|
||||||
|
|
||||||
|
forEach(data.colors, function(color) {
|
||||||
|
out.w("<li>" +
|
||||||
|
escapeXml(color) +
|
||||||
|
"</li>");
|
||||||
|
});
|
||||||
|
|
||||||
|
out.w("</ul>");
|
||||||
|
} else {
|
||||||
|
out.w("<div>No colors!</div>");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
(module.exports = require("marko").c(__filename)).c(create);
|
||||||
|
|||||||
16
test/fixtures/pretty-print/autotest/assignment/actual.json
vendored
Normal file
16
test/fixtures/pretty-print/autotest/assignment/actual.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"type": "TemplateRoot",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "Assignment",
|
||||||
|
"left": "a",
|
||||||
|
"right": "1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"staticVars": {
|
||||||
|
"str": "__helpers.s",
|
||||||
|
"empty": "__helpers.e",
|
||||||
|
"notEmpty": "__helpers.ne",
|
||||||
|
"escapeXml": "__helpers.x"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
test/fixtures/pretty-print/autotest/assignment/expected.json
vendored
Normal file
16
test/fixtures/pretty-print/autotest/assignment/expected.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"type": "TemplateRoot",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "Assignment",
|
||||||
|
"left": "a",
|
||||||
|
"right": "1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"staticVars": {
|
||||||
|
"str": "__helpers.s",
|
||||||
|
"empty": "__helpers.e",
|
||||||
|
"notEmpty": "__helpers.ne",
|
||||||
|
"escapeXml": "__helpers.x"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -67,7 +67,7 @@
|
|||||||
{
|
{
|
||||||
"type": "HtmlElement",
|
"type": "HtmlElement",
|
||||||
"tagName": "ul",
|
"tagName": "ul",
|
||||||
"attributes": [
|
"_attributes": [
|
||||||
{
|
{
|
||||||
"name": "class",
|
"name": "class",
|
||||||
"value": {
|
"value": {
|
||||||
@ -92,7 +92,7 @@
|
|||||||
{
|
{
|
||||||
"type": "HtmlElement",
|
"type": "HtmlElement",
|
||||||
"tagName": "li",
|
"tagName": "li",
|
||||||
"attributes": [
|
"_attributes": [
|
||||||
{
|
{
|
||||||
"name": "class",
|
"name": "class",
|
||||||
"value": {
|
"value": {
|
||||||
135
test/fixtures/pretty-print/autotest/marko-template/expected.json
vendored
Normal file
135
test/fixtures/pretty-print/autotest/marko-template/expected.json
vendored
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
{
|
||||||
|
"type": "TemplateRoot",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "FunctionDeclaration",
|
||||||
|
"name": "create",
|
||||||
|
"params": [
|
||||||
|
"__helpers"
|
||||||
|
],
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "Vars",
|
||||||
|
"kind": "var",
|
||||||
|
"declarations": [
|
||||||
|
{
|
||||||
|
"id": "str",
|
||||||
|
"init": "__helpers.s"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "empty",
|
||||||
|
"init": "__helpers.e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "notEmpty",
|
||||||
|
"init": "__helpers.ne"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Return",
|
||||||
|
"argument": {
|
||||||
|
"type": "FunctionDeclaration",
|
||||||
|
"name": "render",
|
||||||
|
"params": [
|
||||||
|
"data",
|
||||||
|
"out"
|
||||||
|
],
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "TextOutput",
|
||||||
|
"argument": {
|
||||||
|
"type": "Literal",
|
||||||
|
"value": "Hello"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "HtmlOutput",
|
||||||
|
"argument": "data.name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextOutput",
|
||||||
|
"argument": {
|
||||||
|
"type": "Literal",
|
||||||
|
"value": "!"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "If",
|
||||||
|
"test": {
|
||||||
|
"type": "FunctionCall",
|
||||||
|
"callee": "notEmpty",
|
||||||
|
"args": [
|
||||||
|
"data.colors"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "HtmlElement",
|
||||||
|
"tagName": "ul",
|
||||||
|
"_attributes": [
|
||||||
|
{
|
||||||
|
"name": "class",
|
||||||
|
"value": {
|
||||||
|
"type": "Literal",
|
||||||
|
"value": "colors"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "FunctionCall",
|
||||||
|
"callee": "forEach",
|
||||||
|
"args": [
|
||||||
|
"data.colors",
|
||||||
|
{
|
||||||
|
"type": "FunctionDeclaration",
|
||||||
|
"name": null,
|
||||||
|
"params": [
|
||||||
|
"color"
|
||||||
|
],
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "HtmlElement",
|
||||||
|
"tagName": "li",
|
||||||
|
"_attributes": [
|
||||||
|
{
|
||||||
|
"name": "class",
|
||||||
|
"value": {
|
||||||
|
"type": "Literal",
|
||||||
|
"value": "color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "TextOutput",
|
||||||
|
"argument": "color"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"allowSelfClosing": false,
|
||||||
|
"startTagOnly": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"allowSelfClosing": false,
|
||||||
|
"startTagOnly": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"staticVars": {
|
||||||
|
"str": "__helpers.s",
|
||||||
|
"empty": "__helpers.e",
|
||||||
|
"notEmpty": "__helpers.ne",
|
||||||
|
"escapeXml": "__helpers.x"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
test/fixtures/render/autotest/attr-escape-xml/expected.html
vendored
Normal file
1
test/fixtures/render/autotest/attr-escape-xml/expected.html
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div foo=""hello"">Hello World!</div>
|
||||||
3
test/fixtures/render/autotest/attr-escape-xml/template.marko
vendored
Normal file
3
test/fixtures/render/autotest/attr-escape-xml/template.marko
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<div foo='\"hello\"'>
|
||||||
|
Hello World!
|
||||||
|
</div>
|
||||||
1
test/fixtures/render/autotest/attr-escape-xml/test.js
vendored
Normal file
1
test/fixtures/render/autotest/attr-escape-xml/test.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
exports.templateData = {};
|
||||||
@ -1,5 +1,3 @@
|
|||||||
<var name="myAttrs" value="data.myAttrs"/>
|
<div attrs=data.myAttrs data-encoding='"hello"'>
|
||||||
|
|
||||||
<div attrs="myAttrs" data-encoding=""hello"">
|
|
||||||
Hello World!
|
Hello World!
|
||||||
</div>
|
</div>
|
||||||
@ -12,9 +12,15 @@ var autotest = require('./autotest');
|
|||||||
describe('compiler/pretty-print', function() {
|
describe('compiler/pretty-print', function() {
|
||||||
var autoTestDir = path.join(__dirname, 'fixtures/pretty-print/autotest');
|
var autoTestDir = path.join(__dirname, 'fixtures/pretty-print/autotest');
|
||||||
|
|
||||||
autotest.scanDir(autoTestDir, function run(dir) {
|
autotest.scanDir(
|
||||||
var getAST = require(path.join(dir, 'index.js'));
|
autoTestDir,
|
||||||
var ast = getAST(builder);
|
function run(dir) {
|
||||||
return JSON.stringify(ast, null, 2);
|
var getAST = require(path.join(dir, 'index.js'));
|
||||||
});
|
var ast = getAST(builder);
|
||||||
|
return ast;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deepEqual: true,
|
||||||
|
compareExtension: '.json'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user