react / wstein / node_modules / jest-cli / node_modules / istanbul / node_modules / handlebars / dist / cjs / handlebars / compiler / whitespace-control.js
80728 views"use strict";1var Visitor = require("./visitor")["default"];23function WhitespaceControl() {4}5WhitespaceControl.prototype = new Visitor();67WhitespaceControl.prototype.Program = function(program) {8var isRoot = !this.isRootSeen;9this.isRootSeen = true;1011var body = program.body;12for (var i = 0, l = body.length; i < l; i++) {13var current = body[i],14strip = this.accept(current);1516if (!strip) {17continue;18}1920var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),21_isNextWhitespace = isNextWhitespace(body, i, isRoot),2223openStandalone = strip.openStandalone && _isPrevWhitespace,24closeStandalone = strip.closeStandalone && _isNextWhitespace,25inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;2627if (strip.close) {28omitRight(body, i, true);29}30if (strip.open) {31omitLeft(body, i, true);32}3334if (inlineStandalone) {35omitRight(body, i);3637if (omitLeft(body, i)) {38// If we are on a standalone node, save the indent info for partials39if (current.type === 'PartialStatement') {40// Pull out the whitespace from the final line41current.indent = (/([ \t]+$)/).exec(body[i-1].original)[1];42}43}44}45if (openStandalone) {46omitRight((current.program || current.inverse).body);4748// Strip out the previous content node if it's whitespace only49omitLeft(body, i);50}51if (closeStandalone) {52// Always strip the next node53omitRight(body, i);5455omitLeft((current.inverse || current.program).body);56}57}5859return program;60};61WhitespaceControl.prototype.BlockStatement = function(block) {62this.accept(block.program);63this.accept(block.inverse);6465// Find the inverse program that is involed with whitespace stripping.66var program = block.program || block.inverse,67inverse = block.program && block.inverse,68firstInverse = inverse,69lastInverse = inverse;7071if (inverse && inverse.chained) {72firstInverse = inverse.body[0].program;7374// Walk the inverse chain to find the last inverse that is actually in the chain.75while (lastInverse.chained) {76lastInverse = lastInverse.body[lastInverse.body.length-1].program;77}78}7980var strip = {81open: block.openStrip.open,82close: block.closeStrip.close,8384// Determine the standalone candiacy. Basically flag our content as being possibly standalone85// so our parent can determine if we actually are standalone86openStandalone: isNextWhitespace(program.body),87closeStandalone: isPrevWhitespace((firstInverse || program).body)88};8990if (block.openStrip.close) {91omitRight(program.body, null, true);92}9394if (inverse) {95var inverseStrip = block.inverseStrip;9697if (inverseStrip.open) {98omitLeft(program.body, null, true);99}100101if (inverseStrip.close) {102omitRight(firstInverse.body, null, true);103}104if (block.closeStrip.open) {105omitLeft(lastInverse.body, null, true);106}107108// Find standalone else statments109if (isPrevWhitespace(program.body)110&& isNextWhitespace(firstInverse.body)) {111112omitLeft(program.body);113omitRight(firstInverse.body);114}115} else {116if (block.closeStrip.open) {117omitLeft(program.body, null, true);118}119}120121return strip;122};123124WhitespaceControl.prototype.MustacheStatement = function(mustache) {125return mustache.strip;126};127128WhitespaceControl.prototype.PartialStatement =129WhitespaceControl.prototype.CommentStatement = function(node) {130/* istanbul ignore next */131var strip = node.strip || {};132return {133inlineStandalone: true,134open: strip.open,135close: strip.close136};137};138139140function isPrevWhitespace(body, i, isRoot) {141if (i === undefined) {142i = body.length;143}144145// Nodes that end with newlines are considered whitespace (but are special146// cased for strip operations)147var prev = body[i-1],148sibling = body[i-2];149if (!prev) {150return isRoot;151}152153if (prev.type === 'ContentStatement') {154return (sibling || !isRoot ? (/\r?\n\s*?$/) : (/(^|\r?\n)\s*?$/)).test(prev.original);155}156}157function isNextWhitespace(body, i, isRoot) {158if (i === undefined) {159i = -1;160}161162var next = body[i+1],163sibling = body[i+2];164if (!next) {165return isRoot;166}167168if (next.type === 'ContentStatement') {169return (sibling || !isRoot ? (/^\s*?\r?\n/) : (/^\s*?(\r?\n|$)/)).test(next.original);170}171}172173// Marks the node to the right of the position as omitted.174// I.e. {{foo}}' ' will mark the ' ' node as omitted.175//176// If i is undefined, then the first child will be marked as such.177//178// If mulitple is truthy then all whitespace will be stripped out until non-whitespace179// content is met.180function omitRight(body, i, multiple) {181var current = body[i == null ? 0 : i + 1];182if (!current || current.type !== 'ContentStatement' || (!multiple && current.rightStripped)) {183return;184}185186var original = current.value;187current.value = current.value.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), '');188current.rightStripped = current.value !== original;189}190191// Marks the node to the left of the position as omitted.192// I.e. ' '{{foo}} will mark the ' ' node as omitted.193//194// If i is undefined then the last child will be marked as such.195//196// If mulitple is truthy then all whitespace will be stripped out until non-whitespace197// content is met.198function omitLeft(body, i, multiple) {199var current = body[i == null ? body.length - 1 : i - 1];200if (!current || current.type !== 'ContentStatement' || (!multiple && current.leftStripped)) {201return;202}203204// We omit the last node if it's whitespace only and not preceeded by a non-content node.205var original = current.value;206current.value = current.value.replace(multiple ? (/\s+$/) : (/[ \t]+$/), '');207current.leftStripped = current.value !== original;208return current.leftStripped;209}210211exports["default"] = WhitespaceControl;212213