finished porting changes
diff --git a/escodegen.js b/escodegen.js
index bd5424f..331a16c 100644
--- a/escodegen.js
+++ b/escodegen.js
@@ -715,11 +715,11 @@
return '//' + comment.value;
} else {
// Always use LineTerminator
- var comment = '//' + comment.value + '\n';
+ var result = '//' + comment.value;
if (!preserveBlankLines) {
- comment += '\n';
+ result += '\n';
}
- return comment;
+ return result;
}
}
if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
@@ -841,6 +841,21 @@
return result;
}
+ function generateBlankLines(start, end, result) {
+ var j;
+
+ var newlineCount = 0;
+ for (j = start; j < end; j++) {
+ if (sourceCode[j] === '\n') {
+ newlineCount++;
+ }
+ }
+
+ for (j = 1; j < newlineCount; j++) {
+ result.push(newline);
+ }
+ }
+
function parenthesize(text, current, should) {
if (current < should) {
return ['(', text, ')'];
@@ -1053,22 +1068,82 @@
CodeGenerator.Statement = {
BlockStatement: function (stmt, flags) {
+ var range, content;
var result = ['{', newline], that = this;
withIndent(function () {
+ // handle functions without any code
+ if (stmt.body.length === 0 && preserveBlankLines) {
+ range = stmt.range;
+ if (range[1] - range[0] > 2) {
+ content = sourceCode.substring(range[0] + 1, range[1] - 1);
+ if (content[0] === '\n') {
+ result = ['{'];
+ }
+ result.push(content);
+ }
+ }
+
var i, iz, fragment, bodyFlags;
bodyFlags = S_TFFF;
if (flags & F_FUNC_BODY) {
bodyFlags |= F_DIRECTIVE_CTX;
}
+
for (i = 0, iz = stmt.body.length; i < iz; ++i) {
+ if (preserveBlankLines) {
+ // handle spaces before the first line
+ if (i === 0) {
+ if (stmt.body[0].leadingComments) {
+ range = stmt.body[0].leadingComments[0].extendedRange;
+ content = sourceCode.substring(range[0], range[1]);
+ if (content[0] === '\n') {
+ result = ['{'];
+ }
+ }
+ if (!stmt.body[0].leadingComments) {
+ generateBlankLines(stmt.range[0], stmt.body[0].range[0], result);
+ }
+ }
+
+ // handle spaces between lines
+ if (i > 0) {
+ if (!stmt.body[i - 1].trailingComments && !stmt.body[i].leadingComments) {
+ generateBlankLines(stmt.body[i - 1].range[1], stmt.body[i].range[0], result);
+ }
+ }
+ }
+
if (i === iz - 1) {
bodyFlags |= F_SEMICOLON_OPT;
}
- fragment = addIndent(that.generateStatement(stmt.body[i], bodyFlags));
+
+ if (stmt.body[i].leadingComments && preserveBlankLines) {
+ fragment = that.generateStatement(stmt.body[i], bodyFlags);
+ } else {
+ fragment = addIndent(that.generateStatement(stmt.body[i], bodyFlags));
+ }
+
result.push(fragment);
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
- result.push(newline);
+ if (preserveBlankLines && i < iz - 1) {
+ // don't add a new line if there are leading coments
+ // in the next statement
+ if (!stmt.body[i + 1].leadingComments) {
+ result.push(newline);
+ }
+ } else {
+ result.push(newline);
+ }
+ }
+
+ if (preserveBlankLines) {
+ // handle spaces after the last line
+ if (i === iz - 1) {
+ if (!stmt.body[i].trailingComments) {
+ generateBlankLines(stmt.body[i].range[1], stmt.range[1], result);
+ }
+ }
}
}
});
@@ -1254,21 +1329,6 @@
return result;
},
- BlankLines: function (start, end, result) {
- var j;
-
- var newlineCount = 0;
- for (j = start; j < end; j++) {
- if (sourceCode[j] === '\n') {
- newlineCount++;
- }
- }
-
- for (j = 1; j < newlineCount; j++) {
- result.push(newline);
- }
- },
-
ImportDeclaration: function (stmt, flags) {
// ES6: 15.2.1 valid import declarations:
// - import ImportClause FromClause ;
@@ -1618,10 +1678,42 @@
if (!safeConcatenation && i === iz - 1) {
bodyFlags |= F_SEMICOLON_OPT;
}
+
+ if (preserveBlankLines) {
+ // handle spaces before the first line
+ if (i === 0) {
+ if (!stmt.body[0].leadingComments) {
+ generateBlankLines(stmt.range[0], stmt.body[i].range[0], result);
+ }
+ }
+
+ // handle spaces between lines
+ if (i > 0) {
+ if (!stmt.body[i - 1].trailingComments && !stmt.body[i].leadingComments) {
+ generateBlankLines(stmt.body[i - 1].range[1], stmt.body[i].range[0], result);
+ }
+ }
+ }
+
fragment = addIndent(this.generateStatement(stmt.body[i], bodyFlags));
result.push(fragment);
if (i + 1 < iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
- result.push(newline);
+ if (preserveBlankLines) {
+ if (!stmt.body[i + 1].leadingComments) {
+ result.push(newline);
+ }
+ } else {
+ result.push(newline);
+ }
+ }
+
+ if (preserveBlankLines) {
+ // handle spaces after the last line
+ if (i === iz - 1) {
+ if (!stmt.body[i].trailingComments) {
+ generateBlankLines(stmt.body[i].range[1], stmt.range[1], result);
+ }
+ }
}
}
return result;
@@ -2401,6 +2493,8 @@
directive = options.directive;
parse = json ? null : options.parse;
sourceMap = options.sourceMap;
+ sourceCode = options.sourceCode;
+ preserveBlankLines = options.format.preserveBlankLines && sourceCode !== null;
extra = options;
if (sourceMap) {
diff --git a/test/preserve-blank-lines.js b/test/preserve-blank-lines.js
new file mode 100644
index 0000000..ca3b730
--- /dev/null
+++ b/test/preserve-blank-lines.js
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2011-2013 Yusuke Suzuki <utatane.tea@gmail.com>
+ Copyright (C) 2014 Kevin Barabash <kevinb7@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+var fs = require('fs'),
+ esprima = require('esprima'),
+ escodegen = require('./loader'),
+ chai = require('chai'),
+ expect = chai.expect;
+
+function test(code, expected) {
+ var tree, actual, options, StringObject;
+
+ // alias, so that JSLint does not complain.
+ StringObject = String;
+
+ options = {
+ range: true,
+ tokens: true,
+ comment: true
+ };
+
+ tree = esprima.parse(code, options);
+ tree = escodegen.attachComments(tree, tree.comments, tree.tokens);
+
+ options = {
+ comment: true,
+ sourceCode: code,
+ format: {
+ preserveBlankLines: true
+ }
+ };
+
+ // for UNIX text comment
+ actual = escodegen.generate(tree, options);
+ expect(actual).to.be.equal(expected);
+}
+
+describe('preserve blank lines test', function () {
+ fs.readdirSync(__dirname + '/preserve-blank-lines').sort().forEach(function(file) {
+ var code, expected, p;
+ if (/\.js$/.test(file) && !/expected\.js$/.test(file)) {
+ it(file, function () {
+ p = file.replace(/\.js$/, '.expected.js');
+ code = fs.readFileSync(__dirname + '/preserve-blank-lines/' + file, 'utf-8');
+ expected = fs.readFileSync(__dirname + '/preserve-blank-lines/' + p, 'utf-8');
+ test(code, expected);
+ });
+ }
+ });
+});
+
+/* vim: set sw=4 ts=4 et tw=80 : */