mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
168 lines
4.4 KiB
JavaScript
168 lines
4.4 KiB
JavaScript
'use strict';
|
|
|
|
var ok = require('assert').ok;
|
|
var Node = require('./Node');
|
|
var Literal = require('./Literal');
|
|
var escapeXml = require('raptor-util/escapeXml');
|
|
|
|
function trim(textNode) {
|
|
if (textNode.preserveWhitespace === true) {
|
|
return;
|
|
}
|
|
|
|
var text = textNode.argument.value;
|
|
var isFirst = textNode.isFirst;
|
|
var isLast = textNode.isLast;
|
|
|
|
if (isFirst) {
|
|
//First child
|
|
text = text.replace(/^\n\s*/g, '');
|
|
}
|
|
if (isLast) {
|
|
//Last child
|
|
text = text.replace(/\n\s*$/g, '');
|
|
}
|
|
if (/^\n\s*$/.test(text)) {
|
|
//Whitespace between elements
|
|
text = '';
|
|
}
|
|
text = text.replace(/\s+/g, ' ');
|
|
textNode.argument.value = text;
|
|
}
|
|
|
|
class Text extends Node {
|
|
constructor(def) {
|
|
super('Text');
|
|
this.argument = def.argument;
|
|
this.escape = def.escape !== false;
|
|
this.normalized = false;
|
|
this.isFirst = false;
|
|
this.isLast = false;
|
|
this.preserveWhitespace = def.preserveWhitespace === true;
|
|
|
|
ok(this.argument, 'Invalid argument');
|
|
}
|
|
|
|
isLiteral() {
|
|
return this.argument instanceof Node && this.argument.type === 'Literal';
|
|
}
|
|
|
|
generateHtmlCode(codegen) {
|
|
this.normalizeText(codegen);
|
|
|
|
|
|
|
|
var argument = this.argument;
|
|
var escape = this.escape !== false;
|
|
|
|
if (argument instanceof Literal) {
|
|
if (!argument.value) {
|
|
return;
|
|
}
|
|
|
|
if (escape === true) {
|
|
argument.value = escapeXml(argument.value.toString());
|
|
}
|
|
} else {
|
|
let builder = codegen.builder;
|
|
|
|
if (escape) {
|
|
// TODO Only escape the parts that need to be escaped if it is a compound expression with static
|
|
// text parts
|
|
argument = builder.functionCall(
|
|
'escapeXml',
|
|
[argument]);
|
|
} else {
|
|
argument = builder.functionCall(builder.identifier('str'), [ argument ]);
|
|
}
|
|
}
|
|
|
|
codegen.addWrite(argument);
|
|
}
|
|
|
|
normalizeText(codegen) {
|
|
if (this.normalized || codegen.context.isPreserveWhitespace() || this.preserveWhitespace === true) {
|
|
return;
|
|
}
|
|
|
|
var parentNode = this.parentNode;
|
|
if (parentNode) {
|
|
if (parentNode.isPreserveWhitespace()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
var container = this.container;
|
|
if (!container) {
|
|
return;
|
|
}
|
|
|
|
var isFirst = true;
|
|
|
|
var currentTextLiteral = null;
|
|
var literalTextNodes = [];
|
|
|
|
container.forEach((curChild) => {
|
|
if (curChild.noOutput) {
|
|
// Skip over AST nodes that produce no HTML output
|
|
return;
|
|
}
|
|
|
|
if (curChild.type === 'Text') {
|
|
curChild.normalized = true;
|
|
}
|
|
|
|
if (curChild.type === 'Text' && curChild.isLiteral()) {
|
|
if (currentTextLiteral &&
|
|
currentTextLiteral.preserveWhitespace === curChild.preserveWhitespace &&
|
|
currentTextLiteral.escape === curChild.escape) {
|
|
currentTextLiteral.argument.value += curChild.argument.value;
|
|
curChild.detach();
|
|
} else {
|
|
currentTextLiteral = curChild;
|
|
literalTextNodes.push(currentTextLiteral);
|
|
if (isFirst) {
|
|
currentTextLiteral.isFirst = true;
|
|
}
|
|
}
|
|
} else {
|
|
currentTextLiteral = null;
|
|
}
|
|
|
|
isFirst = false;
|
|
});
|
|
|
|
if (currentTextLiteral) {
|
|
// Last child text
|
|
currentTextLiteral.isLast = true;
|
|
}
|
|
|
|
literalTextNodes.forEach(trim);
|
|
|
|
|
|
}
|
|
|
|
isWhitespace() {
|
|
var argument = this.argument;
|
|
return (argument instanceof Literal) &&
|
|
(typeof argument.value === 'string') &&
|
|
(argument.value.trim() === '');
|
|
}
|
|
|
|
appendText(text) {
|
|
if (!this.isLiteral()) {
|
|
throw new Error('Text cannot be appended to a non-literal Text node');
|
|
}
|
|
|
|
this.argument.value += text;
|
|
}
|
|
|
|
toJSON() {
|
|
return {
|
|
type: this.type,
|
|
argument: this.argument
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = Text; |