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));
|
||||
}
|
||||
templateRoot.addStaticVar(name, value);
|
||||
return name;
|
||||
}
|
||||
|
||||
generateCode(node, options) {
|
||||
|
||||
@ -30,7 +30,7 @@ class ArrayContainer extends Container {
|
||||
// }
|
||||
|
||||
forEach(callback, thisObj) {
|
||||
var array = this.array;
|
||||
var array = this.array.concat([]);
|
||||
for (var i=0; i<array.length; i++) {
|
||||
var item = array[i];
|
||||
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.allowSelfClosing = false;
|
||||
this.startTagOnly = false;
|
||||
this._dynamicAttributesExpressionArray = undefined;
|
||||
}
|
||||
|
||||
generateHtmlCode(generator) {
|
||||
@ -25,6 +26,7 @@ class HtmlElement extends Node {
|
||||
var startTagOnly = this.startTagOnly;
|
||||
var allowSelfClosing = this.allowSelfClosing;
|
||||
var hasBody = body && body.length;
|
||||
var builder = generator.builder;
|
||||
|
||||
// Starting tag
|
||||
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) {
|
||||
generator.addWriteLiteral('>');
|
||||
} else {
|
||||
@ -94,6 +104,14 @@ class HtmlElement extends Node {
|
||||
}
|
||||
}
|
||||
|
||||
addDynamicAttributes(expression) {
|
||||
if (!this._dynamicAttributesExpressionArray) {
|
||||
this._dynamicAttributesExpressionArray = [];
|
||||
}
|
||||
|
||||
this._dynamicAttributesExpressionArray.push(expression);
|
||||
}
|
||||
|
||||
removeAttribute(name) {
|
||||
if (this._attributes) {
|
||||
this._attributes.removeAttribute(name);
|
||||
@ -111,6 +129,14 @@ class HtmlElement extends Node {
|
||||
get attributes() {
|
||||
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;
|
||||
@ -94,6 +94,15 @@ var coreAttrHandlers = [
|
||||
|
||||
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) {
|
||||
var attributeTransfomer;
|
||||
|
||||
var attributes = el.getAttributes();
|
||||
if (attributes) {
|
||||
for (let i=0, len=attributes.length; i<len; i++) {
|
||||
let attr = attributes[i];
|
||||
let attrName = attr.name;
|
||||
var attrTransformerFunc = attributeTransformers[attrName];
|
||||
if (attrTransformerFunc) {
|
||||
el.removeAttribute(attrName);
|
||||
el.forEachAttribute((attr) => {
|
||||
let attrName = attr.name;
|
||||
var attrTransformerFunc = attributeTransformers[attrName];
|
||||
if (attrTransformerFunc) {
|
||||
el.removeAttribute(attrName);
|
||||
|
||||
if (!attributeTransfomer) {
|
||||
attributeTransfomer = new AttributeTransformer(compiler, el);
|
||||
}
|
||||
attributeTransfomer[attrName](attr, el);
|
||||
if (!attributeTransfomer) {
|
||||
attributeTransfomer = new AttributeTransformer(compiler, el);
|
||||
}
|
||||
attributeTransfomer[attrName](attr, el);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -1,30 +1,47 @@
|
||||
var fs = require('fs');
|
||||
var enabledTest = process.env.TEST;
|
||||
var path = require('path');
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
function autoTest(name, dir, run, options) {
|
||||
var compareExtension = (options && options.compareExtension) || '.js';
|
||||
var isJSON = compareExtension === '.json';
|
||||
|
||||
var actualPath = path.join(dir, 'actual' + compareExtension);
|
||||
var expectedPath = path.join(dir, 'expected' + compareExtension);
|
||||
|
||||
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;
|
||||
|
||||
try {
|
||||
expected = fs.readFileSync(expectedPath, { encoding: 'utf8' });
|
||||
} catch(e) {
|
||||
expected = 'TBD';
|
||||
expected = isJSON ? '"TBD"' : 'TBD';
|
||||
fs.writeFileSync(expectedPath, expected, {encoding: 'utf8'});
|
||||
}
|
||||
|
||||
if (actual !== expected) {
|
||||
throw new Error('Unexpected output for "' + name + '":\nEXPECTED (' + expectedPath + '):\n---------\n' + expected +
|
||||
'\n---------\nACTUAL (' + actualPath + '):\n---------\n' + actual + '\n---------');
|
||||
var expectedJSON;
|
||||
|
||||
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) {
|
||||
|
||||
@ -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",
|
||||
"tagName": "ul",
|
||||
"attributes": [
|
||||
"_attributes": [
|
||||
{
|
||||
"name": "class",
|
||||
"value": {
|
||||
@ -92,7 +92,7 @@
|
||||
{
|
||||
"type": "HtmlElement",
|
||||
"tagName": "li",
|
||||
"attributes": [
|
||||
"_attributes": [
|
||||
{
|
||||
"name": "class",
|
||||
"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="myAttrs" data-encoding=""hello"">
|
||||
<div attrs=data.myAttrs data-encoding='"hello"'>
|
||||
Hello World!
|
||||
</div>
|
||||
@ -12,9 +12,15 @@ var autotest = require('./autotest');
|
||||
describe('compiler/pretty-print', function() {
|
||||
var autoTestDir = path.join(__dirname, 'fixtures/pretty-print/autotest');
|
||||
|
||||
autotest.scanDir(autoTestDir, function run(dir) {
|
||||
var getAST = require(path.join(dir, 'index.js'));
|
||||
var ast = getAST(builder);
|
||||
return JSON.stringify(ast, null, 2);
|
||||
});
|
||||
autotest.scanDir(
|
||||
autoTestDir,
|
||||
function run(dir) {
|
||||
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