diff --git a/lib/svgo.test.js b/lib/svgo.test.js index 405810956..71102b33d 100644 --- a/lib/svgo.test.js +++ b/lib/svgo.test.js @@ -64,6 +64,122 @@ test('allow to disable and customize plugins in preset', () => { `); }); +describe('allow to configure EOL', () => { + test('should respect EOL set to LF', () => { + const svg = ` + + + + Not standard description + + + + `; + const { data } = optimize(svg, { + js2svg: { eol: 'lf', pretty: true, indent: 2 }, + }); + // using toEqual because line endings matter in these tests + expect(data).toEqual( + '\n \n\n' + ); + }); + + test('should respect EOL set to CRLF', () => { + const svg = ` + + + + Not standard description + + + + `; + const { data } = optimize(svg, { + js2svg: { eol: 'crlf', pretty: true, indent: 2 }, + }); + // using toEqual because line endings matter in these tests + expect(data).toEqual( + '\r\n \r\n\r\n' + ); + }); + + test('should default to LF line break for any other EOL values', () => { + const svg = ` + + + + Not standard description + + + + `; + const { data } = optimize(svg, { + js2svg: { eol: 'invalid', pretty: true, indent: 2 }, + }); + // using toEqual because line endings matter in these tests + expect(data).toEqual( + '\n \n\n' + ); + }); +}); + +describe('allow to configure final newline', () => { + test('should not add final newline when unset', () => { + const svg = ` + + + + Not standard description + + + + `; + const { data } = optimize(svg, { js2svg: { eol: 'lf' } }); + // using toEqual because line endings matter in these tests + expect(data).toEqual( + '' + ); + }); + + test('should add final newline when set', () => { + const svg = ` + + + + Not standard description + + + + `; + const { data } = optimize(svg, { + js2svg: { finalNewline: true, eol: 'lf' }, + }); + // using toEqual because line endings matter in these tests + expect(data).toEqual( + '\n' + ); + }); + + test('should not add extra newlines when using pretty: true', () => { + const svg = ` + + + + Not standard description + + + + `; + const { data } = optimize(svg, { + js2svg: { finalNewline: true, pretty: true, indent: 2, eol: 'lf' }, + }); + // using toEqual because line endings matter in these tests + expect(data).toEqual( + '\n \n\n' + ); + }); +}); + test('allow to customize precision for preset', () => { const svg = ` diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js index 0248e36fb..93cda6521 100644 --- a/lib/svgo/coa.js +++ b/lib/svgo/coa.js @@ -54,6 +54,11 @@ module.exports = function makeProgram(program) { ) .option('--pretty', 'Make SVG pretty printed') .option('--indent ', 'Indent number when pretty printing SVGs') + .option( + '--eol ', + 'Line break to use when outputting SVG: lf, crlf. If unspecified, uses platform default.' + ) + .option('--final-newline', 'Ensure SVG ends with a line break') .option( '-r, --recursive', "Use with '--folder'. Optimizes *.svg files in folders recursively." @@ -112,6 +117,13 @@ async function action(args, opts, command) { } } + if (opts.eol != null && opts.eol !== 'lf' && opts.eol !== 'crlf') { + console.error( + "error: option '--eol' must have one of the following values: 'lf' or 'crlf'" + ); + process.exit(1); + } + // --show-plugins if (opts.showPlugins) { showAvailablePlugins(); @@ -185,6 +197,18 @@ async function action(args, opts, command) { } } + // --eol + if (opts.eol) { + config.js2svg = config.js2svg || {}; + config.js2svg.eol = opts.eol; + } + + // --final-newline + if (opts.finalNewline) { + config.js2svg = config.js2svg || {}; + config.js2svg.finalNewline = true; + } + // --output if (output) { if (input.length && input[0] != '-') { diff --git a/lib/svgo/js2svg.js b/lib/svgo/js2svg.js index 69cf52bcf..49bf2c1a6 100644 --- a/lib/svgo/js2svg.js +++ b/lib/svgo/js2svg.js @@ -1,6 +1,6 @@ 'use strict'; -var EOL = require('os').EOL, +var platformEOL = require('os').EOL, textElems = require('../../plugins/_collections.js').textElems; var defaults = { @@ -28,6 +28,8 @@ var defaults = { encodeEntity: encodeEntity, pretty: false, useShortTags: true, + eol: platformEOL === '\r\n' ? 'crlf' : 'lf', + finalNewline: false, }; var entities = { @@ -64,15 +66,21 @@ function JS2SVG(config) { this.config.indent = ' '; } + if (this.config.eol === 'crlf') { + this.eol = '\r\n'; + } else { + this.eol = '\n'; + } + if (this.config.pretty) { - this.config.doctypeEnd += EOL; - this.config.procInstEnd += EOL; - this.config.commentEnd += EOL; - this.config.cdataEnd += EOL; - this.config.tagShortEnd += EOL; - this.config.tagOpenEnd += EOL; - this.config.tagCloseEnd += EOL; - this.config.textEnd += EOL; + this.config.doctypeEnd += this.eol; + this.config.procInstEnd += this.eol; + this.config.commentEnd += this.eol; + this.config.cdataEnd += this.eol; + this.config.tagShortEnd += this.eol; + this.config.tagOpenEnd += this.eol; + this.config.tagCloseEnd += this.eol; + this.config.textEnd += this.eol; } this.indentLevel = 0; @@ -118,6 +126,15 @@ JS2SVG.prototype.convert = function (data) { this.indentLevel--; + if ( + this.config.finalNewline && + this.indentLevel === 0 && + svg.length > 0 && + svg[svg.length - 1] !== '\n' + ) { + svg += this.eol; + } + return { data: svg, info: {