Skip to content

Commit

Permalink
Fixes #964 - allows for configurable line breaks.
Browse files Browse the repository at this point in the history
Use `{ format: { breakWith: 'lf' } }` option to configure what line
break looks like, allows `'crlf'` or `'lf'`, defaults to current system
one so former on Windows and latter on Unix.
  • Loading branch information
jakubpawlowicz committed Aug 2, 2018
1 parent 48808f7 commit 59bf990
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 15 deletions.
1 change: 1 addition & 0 deletions History.md
Expand Up @@ -5,6 +5,7 @@
* Fixed issue [#861](https://github.com/jakubpawlowicz/clean-css/issues/861) - new `transition` property optimizer.
* Fixed issue [#895](https://github.com/jakubpawlowicz/clean-css/issues/895) - ignoring specific styles.
* Fixed issue [#947](https://github.com/jakubpawlowicz/clean-css/issues/947) - selector based filtering.
* Fixed issue [#964](https://github.com/jakubpawlowicz/clean-css/issues/964) - adds configurable line breaks.
* Fixed issue [#986](https://github.com/jakubpawlowicz/clean-css/issues/986) - level 2 optimizations and CSS 4 colors.
* Fixed issue [#1000](https://github.com/jakubpawlowicz/clean-css/issues/1000) - carriage return handling in tokenizer.
* Fixed issue [#1038](https://github.com/jakubpawlowicz/clean-css/issues/1038) - `font-variation-settings` quoting.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -122,6 +122,7 @@ clean-css 4.2 will introduce the following changes / features:
* new `transition` property optimizer;
* preserves any CSS content between `/* clean-css ignore:start */` and `/* clean-css ignore:end */` comments;
* allows filtering based on selector in `transform` callback, see [example](#how-to-apply-arbitrary-transformations-to-css-properties);
* adds configurable line breaks via `format: { breakWith: 'lf' }` option;

## Constructor options

Expand Down Expand Up @@ -264,6 +265,7 @@ new CleanCSS({
beforeBlockEnds: false, // controls if a line break comes before a block ends; defaults to `false`
betweenSelectors: false // controls if a line break comes between selectors; defaults to `false`
},
breakWith: '\n', // controls the new line character, can be `'\r\n'` or `'\n'` (aliased as `'windows'` and `'unix'` or `'crlf'` and `'lf'`); defaults to system one, so former on Windows and latter on Unix
indentBy: 0, // controls number of characters to indent with; defaults to `0`
indentWith: 'space', // controls a character to indent with, can be `'space'` or `'tab'`; defaults to `'space'`
spaces: { // controls where to insert spaces
Expand Down
28 changes: 28 additions & 0 deletions lib/options/format.js
@@ -1,3 +1,5 @@
var systemLineBreak = require('os').EOL;

var override = require('../utils/override');

var Breaks = {
Expand All @@ -12,6 +14,12 @@ var Breaks = {
BetweenSelectors: 'betweenSelectors'
};

var BreakWith = {
CarriageReturnLineFeed: '\r\n',
LineFeed: '\n',
System: systemLineBreak
};

var IndentWith = {
Space: ' ',
Tab: '\t'
Expand All @@ -25,6 +33,7 @@ var Spaces = {

var DEFAULTS = {
breaks: breaks(false),
breakWith: BreakWith.System,
indentBy: 0,
indentWith: IndentWith.Space,
spaces: spaces(false),
Expand Down Expand Up @@ -76,6 +85,10 @@ function formatFrom(source) {
return false;
}

if (typeof source == 'object' && 'breakWith' in source) {
source = override(source, { breakWith: mapBreakWith(source.breakWith) });
}

if (typeof source == 'object' && 'indentBy' in source) {
source = override(source, { indentBy: parseInt(source.indentBy) });
}
Expand Down Expand Up @@ -168,6 +181,21 @@ function normalizeValue(value) {
}
}

function mapBreakWith(value) {
switch (value) {
case 'windows':
case 'crlf':
case BreakWith.CarriageReturnLineFeed:
return BreakWith.CarriageReturnLineFeed;
case 'unix':
case 'lf':
case BreakWith.LineFeed:
return BreakWith.LineFeed;
default:
return systemLineBreak;
}
}

function mapIndentWith(value) {
switch (value) {
case 'space':
Expand Down
13 changes: 6 additions & 7 deletions lib/writer/helpers.js
@@ -1,4 +1,3 @@
var lineBreak = require('os').EOL;
var emptyCharacter = '';

var Breaks = require('../options/format').Breaks;
Expand Down Expand Up @@ -153,7 +152,7 @@ function openBrace(context, where, needsPrefixSpace) {
context.indentWith = context.format.indentWith.repeat(context.indentBy);
return (needsPrefixSpace && allowsSpace(context, Spaces.BeforeBlockBegins) ? Marker.SPACE : emptyCharacter) +
Marker.OPEN_CURLY_BRACKET +
(allowsBreak(context, where) ? lineBreak : emptyCharacter) +
(allowsBreak(context, where) ? context.format.breakWith : emptyCharacter) +
context.indentWith;
} else {
return Marker.OPEN_CURLY_BRACKET;
Expand All @@ -164,10 +163,10 @@ function closeBrace(context, where, beforeBlockEnd, isLast) {
if (context.format) {
context.indentBy -= context.format.indentBy;
context.indentWith = context.format.indentWith.repeat(context.indentBy);
return (allowsBreak(context, Breaks.AfterProperty) || beforeBlockEnd && allowsBreak(context, Breaks.BeforeBlockEnds) ? lineBreak : emptyCharacter) +
return (allowsBreak(context, Breaks.AfterProperty) || beforeBlockEnd && allowsBreak(context, Breaks.BeforeBlockEnds) ? context.format.breakWith : emptyCharacter) +
context.indentWith +
Marker.CLOSE_CURLY_BRACKET +
(isLast ? emptyCharacter : (allowsBreak(context, where) ? lineBreak : emptyCharacter) + context.indentWith);
(isLast ? emptyCharacter : (allowsBreak(context, where) ? context.format.breakWith : emptyCharacter) + context.indentWith);
} else {
return Marker.CLOSE_CURLY_BRACKET;
}
Expand All @@ -181,13 +180,13 @@ function colon(context) {

function semicolon(context, where, isLast) {
return context.format ?
Marker.SEMICOLON + (isLast || !allowsBreak(context, where) ? emptyCharacter : lineBreak + context.indentWith) :
Marker.SEMICOLON + (isLast || !allowsBreak(context, where) ? emptyCharacter : context.format.breakWith + context.indentWith) :
Marker.SEMICOLON;
}

function comma(context) {
return context.format ?
Marker.COMMA + (allowsBreak(context, Breaks.BetweenSelectors) ? lineBreak : emptyCharacter) + context.indentWith :
Marker.COMMA + (allowsBreak(context, Breaks.BetweenSelectors) ? context.format.breakWith : emptyCharacter) + context.indentWith :
Marker.COMMA;
}

Expand Down Expand Up @@ -220,7 +219,7 @@ function all(context, tokens) {
break;
case Token.COMMENT:
store(context, token);
store(context, allowsBreak(context, Breaks.AfterComment) ? lineBreak : emptyCharacter);
store(context, allowsBreak(context, Breaks.AfterComment) ? context.format.breakWith : emptyCharacter);
break;
case Token.RAW:
store(context, token);
Expand Down
6 changes: 2 additions & 4 deletions lib/writer/simple.js
@@ -1,7 +1,5 @@
var all = require('./helpers').all;

var lineBreak = require('os').EOL;

function store(serializeContext, token) {
var value = typeof token == 'string' ?
token :
Expand All @@ -15,8 +13,8 @@ function store(serializeContext, token) {

function wrap(serializeContext, value) {
if (serializeContext.column + value.length > serializeContext.format.wrapAt) {
track(serializeContext, lineBreak);
serializeContext.output.push(lineBreak);
track(serializeContext, serializeContext.format.breakWith);
serializeContext.output.push(serializeContext.format.breakWith);
}
}

Expand Down
5 changes: 2 additions & 3 deletions lib/writer/source-maps.js
@@ -1,7 +1,6 @@
var SourceMapGenerator = require('source-map').SourceMapGenerator;
var all = require('./helpers').all;

var lineBreak = require('os').EOL;
var isRemoteResource = require('../utils/is-remote-resource');

var isWindows = process.platform == 'win32';
Expand All @@ -23,8 +22,8 @@ function store(serializeContext, element) {

function wrap(serializeContext, value) {
if (serializeContext.column + value.length > serializeContext.format.wrapAt) {
track(serializeContext, lineBreak, false);
serializeContext.output.push(lineBreak);
track(serializeContext, serializeContext.format.breakWith, false);
serializeContext.output.push(serializeContext.format.breakWith);
}
}

Expand Down
16 changes: 16 additions & 0 deletions test/integration-test.js
Expand Up @@ -308,6 +308,22 @@ vows.describe('integration tests')
]
}, { format: 'keep-breaks', level: { 1: { specialComments: 0 } } })
)
.addBatch(
optimizerContext('CRLF line breaks', {
'uses specified one': [
'.block{color:red;display:block}',
'.block{color:red;\r\ndisplay:block\r\n}'
]
}, { format: { breaks: { afterProperty: true }, breakWith: 'crlf' } })
)
.addBatch(
optimizerContext('LF line breaks', {
'uses specified one': [
'.block{color:red;display:block}',
'.block{color:red;\ndisplay:block\n}'
]
}, { format: { breaks: { afterProperty: true }, breakWith: 'lf' } })
)
.addBatch(
optimizerContext('selectors', {
'not expand + in selectors mixed with calc methods': [
Expand Down
12 changes: 11 additions & 1 deletion test/options/format-test.js
@@ -1,4 +1,5 @@
var assert = require('assert');
var systemLineBreak = require('os').EOL;

var vows = require('vows');

Expand Down Expand Up @@ -39,6 +40,7 @@ vows.describe(formatFrom)
beforeBlockEnds: false,
betweenSelectors: false
},
breakWith: systemLineBreak,
indentBy: 0,
indentWith: ' ',
spaces: {
Expand All @@ -53,7 +55,7 @@ vows.describe(formatFrom)
},
'hash': {
'topic': function () {
return formatFrom({ breaks: { afterProperty: true }, indentBy: 1 });
return formatFrom({ breaks: { afterProperty: true }, breakWith: '\r\n', indentBy: 1 });
},
'is merged with default': function (formatOptions) {
assert.deepEqual(formatOptions, {
Expand All @@ -68,6 +70,7 @@ vows.describe(formatFrom)
beforeBlockEnds: false,
betweenSelectors: false
},
breakWith: '\r\n',
indentBy: 1,
indentWith: ' ',
spaces: {
Expand Down Expand Up @@ -97,6 +100,7 @@ vows.describe(formatFrom)
beforeBlockEnds: false,
betweenSelectors: false
},
breakWith: systemLineBreak,
indentBy: 2,
indentWith: ' ',
spaces: {
Expand Down Expand Up @@ -126,6 +130,7 @@ vows.describe(formatFrom)
beforeBlockEnds: false,
betweenSelectors: false
},
breakWith: systemLineBreak,
indentBy: 0,
indentWith: '\t',
spaces: {
Expand Down Expand Up @@ -155,6 +160,7 @@ vows.describe(formatFrom)
beforeBlockEnds: false,
betweenSelectors: false
},
breakWith: systemLineBreak,
indentBy: 0,
indentWith: '\t',
spaces: {
Expand Down Expand Up @@ -184,6 +190,7 @@ vows.describe(formatFrom)
beforeBlockEnds: false,
betweenSelectors: false
},
breakWith: systemLineBreak,
indentBy: 3,
indentWith: ' ',
spaces: {
Expand Down Expand Up @@ -213,6 +220,7 @@ vows.describe(formatFrom)
beforeBlockEnds: false,
betweenSelectors: false
},
breakWith: systemLineBreak,
indentBy: 0,
indentWith: '\t',
spaces: {
Expand Down Expand Up @@ -242,6 +250,7 @@ vows.describe(formatFrom)
beforeBlockEnds: true,
betweenSelectors: true
},
breakWith: systemLineBreak,
indentBy: 2,
indentWith: ' ',
spaces: {
Expand Down Expand Up @@ -271,6 +280,7 @@ vows.describe(formatFrom)
beforeBlockEnds: true,
betweenSelectors: false
},
breakWith: systemLineBreak,
indentBy: 0,
indentWith: ' ',
spaces: {
Expand Down

0 comments on commit 59bf990

Please sign in to comment.