diff --git a/.travis.yml b/.travis.yml index 921e6c86..5cccead6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ sudo: false language: node_js node_js: - - "4" - - "6" - "8" + - "10" + - "12" diff --git a/escodegen.js b/escodegen.js index 41b3850f..bbae4935 100644 --- a/escodegen.js +++ b/escodegen.js @@ -79,6 +79,14 @@ return CodeGenerator.Statement.hasOwnProperty(node.type); } + // Get range either by directly accessing .start + .end or accessing .range + function getRange(node) { + if (!("range" in node)) { + return [node.start, node.end]; + } + return node.range; + } + Precedence = { Sequence: 0, Yield: 1, @@ -668,7 +676,7 @@ result = []; extRange = comment.extendedRange; - range = comment.range; + range = getRange(comment); prefix = sourceCode.substring(extRange[0], range[0]); count = (prefix.match(/\n/g) || []).length; @@ -684,7 +692,7 @@ for (i = 1, len = stmt.leadingComments.length; i < len; i++) { comment = stmt.leadingComments[i]; - range = comment.range; + range = getRange(comment); infix = sourceCode.substring(prevRange[1], range[0]); count = (infix.match(/\n/g) || []).length; @@ -726,7 +734,7 @@ if (preserveBlankLines) { comment = stmt.trailingComments[0]; extRange = comment.extendedRange; - range = comment.range; + range = getRange(comment); prefix = sourceCode.substring(extRange[0], range[0]); count = (prefix.match(/\n/g) || []).length; @@ -1023,7 +1031,7 @@ withIndent(function () { // handle functions without any code if (stmt.body.length === 0 && preserveBlankLines) { - range = stmt.range; + range = getRange(stmt); if (range[1] - range[0] > 2) { content = sourceCode.substring(range[0] + 1, range[1] - 1); if (content[0] === '\n') { @@ -1051,14 +1059,14 @@ } } if (!stmt.body[0].leadingComments) { - generateBlankLines(stmt.range[0], stmt.body[0].range[0], result); + generateBlankLines(getRange(stmt)[0], getRange(stmt.body[0])[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); + generateBlankLines(getRange(stmt.body[i - 1])[1], getRange(stmt.body[i])[0], result); } } } @@ -1090,7 +1098,7 @@ // 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); + generateBlankLines(getRange(stmt.body[i])[1], getRange(stmt)[1], result); } } } @@ -1692,14 +1700,14 @@ // handle spaces before the first line if (i === 0) { if (!stmt.body[0].leadingComments) { - generateBlankLines(stmt.range[0], stmt.body[i].range[0], result); + generateBlankLines(getRange(stmt)[0], getRange(stmt.body[i])[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); + generateBlankLines(getRange(stmt.body[i - 1])[1], getRange(stmt.body[i])[0], result); } } } @@ -1720,7 +1728,7 @@ // 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); + generateBlankLines(getRange(stmt.body[i])[1], getRange(stmt)[1], result); } } } diff --git a/gulpfile.js b/gulpfile.js index 590e1274..822807f6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -79,5 +79,5 @@ gulp.task('lint', function () { .pipe(eslint.failOnError()); }); -gulp.task('travis', [ 'lint', 'test' ]); -gulp.task('default', [ 'travis' ]); +gulp.task('travis', gulp.parallel('lint', 'test')); +gulp.task('default', gulp.parallel('travis')); diff --git a/package.json b/package.json index 5e649dde..b6288a22 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,9 @@ "bower-registry-client": "^1.0.0", "chai": "^3.5.0", "commonjs-everywhere": "^0.9.7", - "gulp": "^3.8.10", - "gulp-eslint": "^3.0.1", - "gulp-mocha": "^3.0.1", + "gulp": "^4.0.1", + "gulp-eslint": "^6.0.0", + "gulp-mocha": "^7.0.2", "semver": "^5.1.0" }, "license": "BSD-2-Clause", diff --git a/test/compare-acorn-preserve-blank-lines.js b/test/compare-acorn-preserve-blank-lines.js new file mode 100644 index 00000000..0e267478 --- /dev/null +++ b/test/compare-acorn-preserve-blank-lines.js @@ -0,0 +1,66 @@ +/* + Copyright (C) 2019 Guy Lewin + + 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 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'), + acorn = require('acorn'), + 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; + + tree = acorn.parse(code); + + options = { + sourceCode: code, + format: { + preserveBlankLines: true + } + } + + // for UNIX text comment + actual = escodegen.generate(tree, options).replace(/[\n\r]$/, '') + '\n'; + expect(actual).to.be.equal(expected); +} + +describe('compare acorn preserve blank lines test', function () { + fs.readdirSync(__dirname + '/compare-acorn-preserve-blank-lines').sort().forEach(function(file) { + var code, expected, exp; + if (/\.js$/.test(file) && !/expected\.js$/.test(file)) { + it(file, function () { + exp = file.replace(/\.js$/, '.expected.js'); + code = fs.readFileSync(__dirname + '/compare-acorn-preserve-blank-lines/' + file, 'utf-8'); + expected = fs.readFileSync(__dirname + '/compare-acorn-preserve-blank-lines/' + exp, 'utf-8'); + test(code, expected); + }); + } + }); +}); +/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/test/compare-acorn-preserve-blank-lines/block-statement.expected.js b/test/compare-acorn-preserve-blank-lines/block-statement.expected.js new file mode 100644 index 00000000..b90c392a --- /dev/null +++ b/test/compare-acorn-preserve-blank-lines/block-statement.expected.js @@ -0,0 +1,2 @@ +{ + } diff --git a/test/compare-acorn-preserve-blank-lines/block-statement.js b/test/compare-acorn-preserve-blank-lines/block-statement.js new file mode 100644 index 00000000..b90c392a --- /dev/null +++ b/test/compare-acorn-preserve-blank-lines/block-statement.js @@ -0,0 +1,2 @@ +{ + } diff --git a/test/range.js b/test/range.js new file mode 100644 index 00000000..0059ee54 --- /dev/null +++ b/test/range.js @@ -0,0 +1,85 @@ +/* + Copyright (C) 2019 Guy Lewin + + 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 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(tree) { + var tree, actual; + var code = "{\n }"; + var options = { + sourceCode: code, + format: { + preserveBlankLines: true + } + }; + + actual = escodegen.generate(tree, options); + expect(actual).to.be.equal(code); +} + +describe('test building trees with and without range', function () { + it("with range - Esprima built", function () { + // Parsed by Esprima + test({ + "type": "Program", + "body": [{ + "type": "BlockStatement", + "body": [], + "range": [ + 0, + 7 + ] + }], + "sourceType": "module", + "range": [ + 0, + 7 + ] + }); + }); + + it("without range - Acorn built", function () { + // Parsed by Acorn + test({ + "type": "Program", + "start": 0, + "end": 7, + "body": [{ + "type": "BlockStatement", + "start": 0, + "end": 7, + "body": [] + }], + "sourceType": "module" + }); + }); +}); + +/* vim: set sw=4 ts=4 et tw=80 : */