react / wstein / node_modules / jest-cli / node_modules / istanbul / node_modules / handlebars / lib / handlebars / compiler / whitespace-control.js
80713 viewsimport Visitor from "./visitor";12function WhitespaceControl() {3}4WhitespaceControl.prototype = new Visitor();56WhitespaceControl.prototype.Program = function(program) {7var isRoot = !this.isRootSeen;8this.isRootSeen = true;910var body = program.body;11for (var i = 0, l = body.length; i < l; i++) {12var current = body[i],13strip = this.accept(current);1415if (!strip) {16continue;17}1819var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),20_isNextWhitespace = isNextWhitespace(body, i, isRoot),2122openStandalone = strip.openStandalone && _isPrevWhitespace,23closeStandalone = strip.closeStandalone && _isNextWhitespace,24inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;2526if (strip.close) {27omitRight(body, i, true);28}29if (strip.open) {30omitLeft(body, i, true);31}3233if (inlineStandalone) {34omitRight(body, i);3536if (omitLeft(body, i)) {37// If we are on a standalone node, save the indent info for partials38if (current.type === 'PartialStatement') {39// Pull out the whitespace from the final line40current.indent = (/([ \t]+$)/).exec(body[i-1].original)[1];41}42}43}44if (openStandalone) {45omitRight((current.program || current.inverse).body);4647// Strip out the previous content node if it's whitespace only48omitLeft(body, i);49}50if (closeStandalone) {51// Always strip the next node52omitRight(body, i);5354omitLeft((current.inverse || current.program).body);55}56}5758return program;59};60WhitespaceControl.prototype.BlockStatement = function(block) {61this.accept(block.program);62this.accept(block.inverse);6364// Find the inverse program that is involed with whitespace stripping.65var program = block.program || block.inverse,66inverse = block.program && block.inverse,67firstInverse = inverse,68lastInverse = inverse;6970if (inverse && inverse.chained) {71firstInverse = inverse.body[0].program;7273// Walk the inverse chain to find the last inverse that is actually in the chain.74while (lastInverse.chained) {75lastInverse = lastInverse.body[lastInverse.body.length-1].program;76}77}7879var strip = {80open: block.openStrip.open,81close: block.closeStrip.close,8283// Determine the standalone candiacy. Basically flag our content as being possibly standalone84// so our parent can determine if we actually are standalone85openStandalone: isNextWhitespace(program.body),86closeStandalone: isPrevWhitespace((firstInverse || program).body)87};8889if (block.openStrip.close) {90omitRight(program.body, null, true);91}9293if (inverse) {94var inverseStrip = block.inverseStrip;9596if (inverseStrip.open) {97omitLeft(program.body, null, true);98}99100if (inverseStrip.close) {101omitRight(firstInverse.body, null, true);102}103if (block.closeStrip.open) {104omitLeft(lastInverse.body, null, true);105}106107// Find standalone else statments108if (isPrevWhitespace(program.body)109&& isNextWhitespace(firstInverse.body)) {110111omitLeft(program.body);112omitRight(firstInverse.body);113}114} else {115if (block.closeStrip.open) {116omitLeft(program.body, null, true);117}118}119120return strip;121};122123WhitespaceControl.prototype.MustacheStatement = function(mustache) {124return mustache.strip;125};126127WhitespaceControl.prototype.PartialStatement =128WhitespaceControl.prototype.CommentStatement = function(node) {129/* istanbul ignore next */130var strip = node.strip || {};131return {132inlineStandalone: true,133open: strip.open,134close: strip.close135};136};137138139function isPrevWhitespace(body, i, isRoot) {140if (i === undefined) {141i = body.length;142}143144// Nodes that end with newlines are considered whitespace (but are special145// cased for strip operations)146var prev = body[i-1],147sibling = body[i-2];148if (!prev) {149return isRoot;150}151152if (prev.type === 'ContentStatement') {153return (sibling || !isRoot ? (/\r?\n\s*?$/) : (/(^|\r?\n)\s*?$/)).test(prev.original);154}155}156function isNextWhitespace(body, i, isRoot) {157if (i === undefined) {158i = -1;159}160161var next = body[i+1],162sibling = body[i+2];163if (!next) {164return isRoot;165}166167if (next.type === 'ContentStatement') {168return (sibling || !isRoot ? (/^\s*?\r?\n/) : (/^\s*?(\r?\n|$)/)).test(next.original);169}170}171172// Marks the node to the right of the position as omitted.173// I.e. {{foo}}' ' will mark the ' ' node as omitted.174//175// If i is undefined, then the first child will be marked as such.176//177// If mulitple is truthy then all whitespace will be stripped out until non-whitespace178// content is met.179function omitRight(body, i, multiple) {180var current = body[i == null ? 0 : i + 1];181if (!current || current.type !== 'ContentStatement' || (!multiple && current.rightStripped)) {182return;183}184185var original = current.value;186current.value = current.value.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), '');187current.rightStripped = current.value !== original;188}189190// Marks the node to the left of the position as omitted.191// I.e. ' '{{foo}} will mark the ' ' node as omitted.192//193// If i is undefined then the last child will be marked as such.194//195// If mulitple is truthy then all whitespace will be stripped out until non-whitespace196// content is met.197function omitLeft(body, i, multiple) {198var current = body[i == null ? body.length - 1 : i - 1];199if (!current || current.type !== 'ContentStatement' || (!multiple && current.leftStripped)) {200return;201}202203// We omit the last node if it's whitespace only and not preceeded by a non-content node.204var original = current.value;205current.value = current.value.replace(multiple ? (/\s+$/) : (/[ \t]+$/), '');206current.leftStripped = current.value !== original;207return current.leftStripped;208}209210export default WhitespaceControl;211212213