UNPKG

@marko/prettyprint

Version:

Prettyprint Marko template files in the syntax of your choice

245 lines (197 loc) 7.09 kB
"use strict"; var printers = require("./printers"); var Writer = require("./util/Writer"); var hasLineBreaks = require("./util/hasLineBreaks"); var isInlineComment = require("./util/isInlineComment"); var formattingTags = require("./formatting-tags"); var constants = require("./constants"); var SYNTAX_HTML = constants.SYNTAX_HTML; const breakAfterTags = { class: true, static: true, style: true }; function inspectNodes(nodes) { var allSimple = true; var hasSpaceAfterIndexes = {}; var inlineCommentIndexes = {}; var hasSpecialNode = false; var preserveWhitespace = false; for (let i = 0; i < nodes.length; i++) { let child = nodes[i]; if (child.type === "Text") { var text = child.argument.value; if (!/\s+$/.test(text)) { hasSpaceAfterIndexes[i] = false; } if (i > 0 && !/^\s+/.test(text)) { hasSpaceAfterIndexes[i - 1] = false; } } else if (child.type === "HtmlElement") { if (!formattingTags[child.tagName]) { allSimple = false; } if (child.tagName === "marko-compiler-options" && child.hasAttribute("preserve-whitespace")) { preserveWhitespace = true; } } else if (child.type === "HtmlComment") { let prev = i > 0 ? nodes[i - 1] : undefined; let next = i < nodes.length - 1 ? nodes[i + 1] : undefined; if (isInlineComment(child, prev, next)) { inlineCommentIndexes[i] = true; } } else { hasSpecialNode = true; } } return { hasSpaceAfterIndexes, inlineCommentIndexes, allSimple, hasSpecialNode, preserveWhitespace }; } module.exports = function printNodes(nodes, printContext, inputWriter) { var inspected = inspectNodes(nodes); var hasSpaceAfterIndexes = inspected.hasSpaceAfterIndexes; var allSimple = inspected.allSimple; var inlineCommentIndexes = inspected.inlineCommentIndexes; if (inspected.preserveWhitespace) { printContext = printContext.create({ preserveWhitespace: true, syntax: SYNTAX_HTML }); } // console.log('------'); // console.log('nodes: ' + JSON.stringify(nodes, null, 2)); // console.log('inspected', JSON.stringify(inspected, null, 4)); // console.log('----'); var writer = inputWriter; var wrapHtmlBlock = false; var avoidLineBreaks = allSimple || Object.keys(hasSpaceAfterIndexes).length || Object.keys(inlineCommentIndexes).length; if (inspected.hasSpecialNode) { avoidLineBreaks = false; } if (printContext.depth === 0) { avoidLineBreaks = false; } if (printContext.preserveWhitespace === true) { avoidLineBreaks = false; } if (avoidLineBreaks) { if (printContext.isConciseSyntax) { wrapHtmlBlock = true; writer = new Writer(writer.col); printContext = printContext.create({ forceHtml: true, syntax: SYNTAX_HTML }); } else { printContext = printContext.create({ forceHtml: true }); } } let prevChild; nodes.forEach((child, i) => { var childWriter = new Writer(writer.col); if (printContext.preserveWhitespace !== true && printContext.depth === 0 && prevChild) { // Insert line break after a group of imports if (child.tagName !== "import" && prevChild.tagName === "import") { writer.write(printContext.eol); } // Insert line break between certain top-level tags if (breakAfterTags[prevChild.tagName]) { writer.write(printContext.eol); } } printers.printNode(child, printContext, childWriter); var childOutput = childWriter.getOutput(); if (childOutput.length) { if (printContext.isHtmlSyntax && printContext.preserveWhitespace === true) { // Short circuit if we are preserving whitespace writer.write(childOutput); return; } if (writer.getOutput().endsWith(printContext.eol)) { writer.write(printContext.currentIndentString); } writer.write(HTMLTrim(childOutput, child, prevChild, printContext.isHtmlSyntax)); if (avoidLineBreaks) { if (child.type === "Text" || child.type === "HtmlElement" || child.type === "HtmlComment") { if (hasSpaceAfterIndexes[i] !== false) { if (inlineCommentIndexes[i + 1]) { writer.write(" "); } else if (inlineCommentIndexes[i]) { writer.write(" "); } else if (allSimple) { writer.write(" "); } else { writer.write(printContext.eol); } } } else { writer.write(printContext.eol); } } else { writer.write(printContext.eol); } } prevChild = child; }); if (printContext.isHtmlSyntax && printContext.preserveWhitespace !== true) { var completeRTrim = avoidLineBreaks && allSimple; writer.rtrim(completeRTrim); writer.write(printContext.eol); if (wrapHtmlBlock) { var wrappedOutput = writer.getOutput().trim(); if (hasLineBreaks(wrappedOutput)) { if (!inputWriter.getOutput().endsWith(printContext.eol + printContext.currentIndentString)) { if (!inputWriter.getOutput().endsWith(printContext.eol)) { inputWriter.write(printContext.eol); } inputWriter.write(printContext.currentIndentString); } inputWriter.write("---" + printContext.eol); inputWriter.write(printContext.currentIndentString); inputWriter.write(wrappedOutput); if (!inputWriter.getOutput().endsWith(printContext.eol + printContext.currentIndentString)) { inputWriter.write(printContext.eol + printContext.currentIndentString); } inputWriter.write("---" + printContext.eol); } else { inputWriter.write(printContext.currentIndentString); if (wrappedOutput.startsWith("<!--")) { inputWriter.write(wrappedOutput); } else { inputWriter.write("-- " + wrappedOutput); } } } if (!inputWriter.getOutput().endsWith(printContext.eol)) { inputWriter.write(printContext.eol); } } }; function HTMLTrim(content, child, prevChild, isHtmlSyntax) { var startWhitespace = /^\s*/.exec(content)[0]; var endWhitespace = /\s*$/.exec(content)[0]; content = content.slice(startWhitespace.length, -1 * endWhitespace.length || undefined); if (child.type === "Text") { if (startWhitespace && prevChild && prevChild.type === "Text") { content = " " + content; } if (endWhitespace && child.nextSibling && child.nextSibling.type === "Text") { content += " "; } } if (isHtmlSyntax && child.type === "HtmlElement") { //check if next node is Text with just whitespace as content var nextNode = child.nextSibling; if (nextNode && nextNode.type === "Text" && nextNode.argument && nextNode.argument.value && nextNode.argument.value.trim() === "") { if (!nextNode.argument.value.match(/^\n+/) && !nextNode.argument.value.match(/\n+$/)) { content += " "; } } } return content; }