mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
use TemplateLiteral node
This commit is contained in:
parent
eb51003030
commit
1eb2842d23
6
package-lock.json
generated
6
package-lock.json
generated
@ -2957,9 +2957,9 @@
|
||||
}
|
||||
},
|
||||
"htmljs-parser": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/htmljs-parser/-/htmljs-parser-2.3.2.tgz",
|
||||
"integrity": "sha1-HMW/mCSgkcKIILM+r3gIOo6qhWw=",
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/htmljs-parser/-/htmljs-parser-2.5.0.tgz",
|
||||
"integrity": "sha512-1P/WMHVYA+hZdVPmkwlvzBR/rp/VDX4X41Jyd94NpSz9l4QH5V8sOIXdtpLbUdvgI2IucpITIflW7iLgL5oKkA==",
|
||||
"requires": {
|
||||
"char-props": "^0.1.5",
|
||||
"complain": "^1.0.0"
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
"events": "^1.0.2",
|
||||
"events-light": "^1.0.0",
|
||||
"he": "^1.1.0",
|
||||
"htmljs-parser": "^2.3.2",
|
||||
"htmljs-parser": "^2.5.0",
|
||||
"lasso-caching-fs": "^1.0.1",
|
||||
"lasso-modules-client": "^2.0.4",
|
||||
"lasso-package-root": "^1.0.1",
|
||||
|
||||
@ -40,6 +40,7 @@ var ArrayExpression = require("./ast/ArrayExpression");
|
||||
var Property = require("./ast/Property");
|
||||
var VariableDeclarator = require("./ast/VariableDeclarator");
|
||||
var ThisExpression = require("./ast/ThisExpression");
|
||||
var TemplateLiteral = require("./ast/TemplateLiteral");
|
||||
var Expression = require("./ast/Expression");
|
||||
var Scriptlet = require("./ast/Scriptlet");
|
||||
var ContainerNode = require("./ast/ContainerNode");
|
||||
@ -53,7 +54,6 @@ var parseExpression = require("./util/parseExpression");
|
||||
var parseStatement = require("./util/parseStatement");
|
||||
var parseJavaScriptArgs = require("./util/parseJavaScriptArgs");
|
||||
var parseJavaScriptParams = require("./util/parseJavaScriptParams");
|
||||
var replacePlaceholderEscapeFuncs = require("./util/replacePlaceholderEscapeFuncs");
|
||||
var isValidJavaScriptIdentifier = require("./util/isValidJavaScriptIdentifier");
|
||||
|
||||
var DEFAULT_BUILDER;
|
||||
@ -487,8 +487,8 @@ class Builder {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
replacePlaceholderEscapeFuncs(node, context) {
|
||||
return replacePlaceholderEscapeFuncs(node, context);
|
||||
replacePlaceholderEscapeFuncs(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
program(body) {
|
||||
@ -563,6 +563,10 @@ class Builder {
|
||||
return new BinaryExpression({ left, right, operator });
|
||||
}
|
||||
|
||||
templateLiteral(quasis, expressions) {
|
||||
return new TemplateLiteral({ quasis, expressions });
|
||||
}
|
||||
|
||||
templateRoot(body) {
|
||||
return new TemplateRoot({ body });
|
||||
}
|
||||
|
||||
@ -21,17 +21,21 @@ class HtmlJsParser {
|
||||
event.escape
|
||||
);
|
||||
}
|
||||
} else if (event.withinOpenTag || event.withinTagName) {
|
||||
// Don't escape placeholder for dynamic attributes. For example: <div ${data.myAttrs}></div>
|
||||
} else {
|
||||
// placeholder within attribute
|
||||
if (event.escape) {
|
||||
event.value = "$escapeXml(" + event.value + ")";
|
||||
} else {
|
||||
event.value = "$noEscapeXml(" + event.value + ")";
|
||||
}
|
||||
}
|
||||
// placeholder within content
|
||||
},
|
||||
|
||||
onString(event) {
|
||||
if (!event.isStringLiteral) {
|
||||
let value = "";
|
||||
event.stringParts.forEach(part => {
|
||||
if (part.type === "placeholder") {
|
||||
value += "${" + part.value + "}";
|
||||
} else {
|
||||
value += part.replace(/`/g, "\\`");
|
||||
}
|
||||
});
|
||||
event.value = "$nonstandard`" + value + "`";
|
||||
}
|
||||
},
|
||||
|
||||
onCDATA(event) {
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
var ok = require("assert").ok;
|
||||
var extend = require("raptor-util/extend");
|
||||
var Normalizer = require("./Normalizer");
|
||||
var replacePlaceholderEscapeFuncs = require("./util/replacePlaceholderEscapeFuncs");
|
||||
|
||||
var COMPILER_ATTRIBUTE_HANDLERS = {
|
||||
"preserve-whitespace": function(attr, context) {
|
||||
@ -269,10 +268,7 @@ class Parser {
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
attrValue = replacePlaceholderEscapeFuncs(
|
||||
parsedExpression,
|
||||
context
|
||||
);
|
||||
attrValue = parsedExpression;
|
||||
} else {
|
||||
attrValue = null;
|
||||
}
|
||||
|
||||
@ -47,7 +47,8 @@ class Html extends Node {
|
||||
}
|
||||
}
|
||||
|
||||
generateHTMLCode() {
|
||||
generateHTMLCode(codegen) {
|
||||
this.argument = codegen.generateCode(this.argument);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@ -148,6 +148,9 @@ module.exports = function generateCode(node, codegen) {
|
||||
|
||||
return builder.htmlLiteral(attr(name, literalValue));
|
||||
} else if (value != null) {
|
||||
if (value.type === "TemplateLiteral") {
|
||||
value.nonstandard = false;
|
||||
}
|
||||
return generateCodeForExpressionAttr(name, value, escape, codegen);
|
||||
} else if (argument) {
|
||||
return [
|
||||
|
||||
@ -4,6 +4,10 @@ module.exports = function generateCode(node, codegen, vdomUtil) {
|
||||
var context = codegen.context;
|
||||
var builder = codegen.builder;
|
||||
|
||||
if (node.value && node.value.type === "TemplateLiteral") {
|
||||
node.value.nonstandard = false;
|
||||
}
|
||||
|
||||
// node.name = codegen.generateCode(node.name);
|
||||
node.value = codegen.generateCode(node.value);
|
||||
node.isStatic = vdomUtil.isStaticValue(node.value);
|
||||
|
||||
72
src/compiler/ast/TemplateLiteral.js
Normal file
72
src/compiler/ast/TemplateLiteral.js
Normal file
@ -0,0 +1,72 @@
|
||||
"use strict";
|
||||
|
||||
var Node = require("./Node");
|
||||
|
||||
class TemplateLiteral extends Node {
|
||||
constructor(def) {
|
||||
super("TemplateLiteral");
|
||||
this.quasis = def.quasis;
|
||||
this.expressions = def.expressions;
|
||||
this.nonstandard = false;
|
||||
}
|
||||
|
||||
generateCode(codegen) {
|
||||
const context = codegen.context;
|
||||
const builder = context.builder;
|
||||
const parts = [];
|
||||
|
||||
for (let i = 0; i <= this.quasis.length; i++) {
|
||||
const quasi = this.quasis[i];
|
||||
const expr = this.expressions[i];
|
||||
if (quasi || (i === 0 && !this.nonstandard)) {
|
||||
parts.push(builder.literal(quasi));
|
||||
}
|
||||
if (expr) {
|
||||
parts.push(codegen.generateCode(expr));
|
||||
}
|
||||
}
|
||||
|
||||
if (parts.length === 1) return parts[0];
|
||||
|
||||
let expression = builder.binaryExpression(parts[0], "+", parts[1]);
|
||||
|
||||
for (let i = 2; i < parts.length; i++) {
|
||||
expression = builder.binaryExpression(expression, "+", parts[i]);
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
writeCode(writer) {
|
||||
for (let i = 0; i <= this.quasis.length; i++) {
|
||||
const quasi = this.quasis[i];
|
||||
const expr = this.expressions[i];
|
||||
if (quasi || i === 0) {
|
||||
if (i > 0) writer.write("+");
|
||||
writer.write(JSON.stringify(quasi));
|
||||
}
|
||||
if (expr) {
|
||||
writer.write("+");
|
||||
writer.write("(");
|
||||
writer.write(expr);
|
||||
writer.write(")");
|
||||
}
|
||||
}
|
||||
writer.write("\n");
|
||||
}
|
||||
|
||||
toString() {
|
||||
let code = "";
|
||||
let quote = this.nonstandard ? '"' : "`";
|
||||
let escape = new RegExp(quote, "g");
|
||||
for (let i = 0; i <= this.quasis.length; i++) {
|
||||
const quasi = this.quasis[i];
|
||||
const expr = this.expressions[i];
|
||||
if (quasi) code += quasi.replace(escape, `\\${quote}`);
|
||||
if (expr) code += "${" + expr.toString() + "}";
|
||||
}
|
||||
return quote + code + quote;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TemplateLiteral;
|
||||
@ -144,6 +144,24 @@ function parseExpression(src, builder, isExpression) {
|
||||
|
||||
return builder.literal(literalValue);
|
||||
}
|
||||
case "TaggedTemplateExpression": {
|
||||
if (node.tag.name === "$nonstandard") {
|
||||
const quasi = convert(node.quasi);
|
||||
if (quasi) {
|
||||
quasi.nonstandard = true;
|
||||
return quasi;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
case "TemplateLiteral": {
|
||||
const quasis = node.quasis.map(q => q.value.cooked);
|
||||
const expressions = convert(node.expressions);
|
||||
if (expressions) {
|
||||
return builder.templateLiteral(quasis, expressions);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
case "LogicalExpression": {
|
||||
let left = convert(node.left);
|
||||
if (!left) {
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
var AttributePlaceholder = require("../ast/AttributePlaceholder");
|
||||
|
||||
module.exports = function replacePlaceholderEscapeFuncs(node, context) {
|
||||
var walker = context.createWalker({
|
||||
exit: function(node) {
|
||||
if (
|
||||
node.type === "FunctionCall" &&
|
||||
node.callee.type === "Identifier"
|
||||
) {
|
||||
if (node.callee.name === "$noEscapeXml") {
|
||||
return new AttributePlaceholder({
|
||||
escape: false,
|
||||
value: node.args[0]
|
||||
});
|
||||
} else if (node.callee.name === "$escapeXml") {
|
||||
return new AttributePlaceholder({
|
||||
escape: true,
|
||||
value: node.args[0]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return walker.walk(node);
|
||||
};
|
||||
@ -118,10 +118,7 @@ module.exports = function handleComponentEvents() {
|
||||
return;
|
||||
}
|
||||
|
||||
targetMethod = builder.replacePlaceholderEscapeFuncs(
|
||||
parsedArgs[0],
|
||||
context
|
||||
);
|
||||
targetMethod = parsedArgs[0];
|
||||
|
||||
if (parsedArgs.length > 1) {
|
||||
extraArgs = parsedArgs.slice(1);
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
const replacePlaceholderEscapeFuncs = require("../../compiler/util/replacePlaceholderEscapeFuncs");
|
||||
|
||||
module.exports = function codeGenerator(elNode, context) {
|
||||
const attributes = elNode.attributes;
|
||||
const builder = context.builder;
|
||||
@ -17,18 +15,15 @@ module.exports = function codeGenerator(elNode, context) {
|
||||
|
||||
elNode.replaceWith(
|
||||
builder.scriptlet({
|
||||
value: replacePlaceholderEscapeFuncs(
|
||||
builder.parseExpression(
|
||||
elNode.attributes
|
||||
.map(
|
||||
attr =>
|
||||
attr.value == null
|
||||
? attr.name
|
||||
: `${attr.name} = ${attr.rawValue}`
|
||||
)
|
||||
.join(", ")
|
||||
),
|
||||
context
|
||||
value: builder.parseExpression(
|
||||
elNode.attributes
|
||||
.map(
|
||||
attr =>
|
||||
attr.value == null
|
||||
? attr.name
|
||||
: `${attr.name} = ${attr.rawValue}`
|
||||
)
|
||||
.join(", ")
|
||||
)
|
||||
})
|
||||
);
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
const isValidJavaScriptVarName = require("../../compiler/util/isValidJavaScriptVarName");
|
||||
const replacePlaceholderEscapeFuncs = require("../../compiler/util/replacePlaceholderEscapeFuncs");
|
||||
|
||||
module.exports = function nodeFactory(elNode, context) {
|
||||
const attributes = elNode.attributes;
|
||||
@ -50,10 +49,7 @@ module.exports = function nodeFactory(elNode, context) {
|
||||
|
||||
let parsedExpression = val;
|
||||
if (val != null) {
|
||||
parsedExpression = replacePlaceholderEscapeFuncs(
|
||||
builder.parseExpression(val),
|
||||
context
|
||||
);
|
||||
parsedExpression = builder.parseExpression(val);
|
||||
}
|
||||
|
||||
return builder.variableDeclarator(name, parsedExpression);
|
||||
|
||||
@ -7,7 +7,7 @@ var marko_template = module.exports = require("marko/src/html").t(__filename),
|
||||
marko_defineComponent = components_helpers.c,
|
||||
marko_helpers = require("marko/src/runtime/html/helpers"),
|
||||
marko_classAttr = marko_helpers.ca,
|
||||
marko_str = marko_helpers.s,
|
||||
marko_attr = marko_helpers.a,
|
||||
marko_escapeXmlAttr = marko_helpers.xa;
|
||||
|
||||
function render(input, out, __component, component, state) {
|
||||
@ -15,17 +15,14 @@ function render(input, out, __component, component, state) {
|
||||
|
||||
out.w("<div" +
|
||||
marko_classAttr(input.className) +
|
||||
" class2=\"" +
|
||||
marko_str(input.className) +
|
||||
"\" foo=\"a" +
|
||||
marko_attr("class2", "" + input.className) +
|
||||
" foo=\"a" +
|
||||
marko_escapeXmlAttr(input.foo) +
|
||||
"b\" bar=\"a " +
|
||||
marko_escapeXmlAttr(input.foo) +
|
||||
" b\" baz=\"a " +
|
||||
marko_str(input.foo) +
|
||||
" b\" nested=\"a " +
|
||||
marko_str(input.foo + ("nested " + input.bar)) +
|
||||
" b\"></div>");
|
||||
"b\"" +
|
||||
marko_attr("bar", ("a " + input.foo) + " b") +
|
||||
marko_attr("baz", ("a " + input.foo) + " b") +
|
||||
marko_attr("nested", ("a " + (input.foo + ("nested " + input.bar))) + " b") +
|
||||
"></div>");
|
||||
}
|
||||
|
||||
marko_template._ = marko_renderer(render, {
|
||||
|
||||
@ -6,14 +6,14 @@ var marko_template = module.exports = require("marko/src/html").t(__filename),
|
||||
marko_renderer = components_helpers.r,
|
||||
marko_defineComponent = components_helpers.c,
|
||||
marko_helpers = require("marko/src/runtime/html/helpers"),
|
||||
marko_escapeXmlAttr = marko_helpers.xa;
|
||||
marko_attr = marko_helpers.a;
|
||||
|
||||
function render(input, out, __component, component, state) {
|
||||
var data = input;
|
||||
|
||||
out.w("<div foo=\"Hello " +
|
||||
marko_escapeXmlAttr(input.name) +
|
||||
"\"></div>");
|
||||
out.w("<div" +
|
||||
marko_attr("foo", "Hello " + input.name) +
|
||||
"></div>");
|
||||
|
||||
var foo = "Hello " + input.name;
|
||||
}
|
||||
|
||||
@ -0,0 +1 @@
|
||||
<div data-foo=input.foo/>
|
||||
@ -0,0 +1 @@
|
||||
<div data-foo='{"name":"Frank"}'></div><div data-foo='{"name":"Frank"}'></div>
|
||||
@ -0,0 +1,9 @@
|
||||
$ var foo = {
|
||||
name: 'Frank',
|
||||
toString: function() {
|
||||
return this.name;
|
||||
}
|
||||
};
|
||||
|
||||
<tag foo="${foo}"/>
|
||||
<tag foo=foo/>
|
||||
1
test/render/fixtures/attr-value-obj-custom-tag/test.js
Normal file
1
test/render/fixtures/attr-value-obj-custom-tag/test.js
Normal file
@ -0,0 +1 @@
|
||||
exports.templateData = {};
|
||||
Loading…
x
Reference in New Issue
Block a user