Commit 1e075931 by Adeel Mujahid

Merge pull request #792 from am11/master

Feature: Configurable linefeed and indent
parents 0558325e 279d14bb
...@@ -89,7 +89,7 @@ When returning or calling `done()` with `{ contents: "String" }`, the string val ...@@ -89,7 +89,7 @@ When returning or calling `done()` with `{ contents: "String" }`, the string val
Starting from v3.0.0, `this` refers to a contextual scope for the immediate run of `sass.render` or `sass.renderSync` Starting from v3.0.0, `this` refers to a contextual scope for the immediate run of `sass.render` or `sass.renderSync`
### functions ### functions (>= v3.0.0)
`functions` is an `Object` that holds a collection of custom functions that may be invoked by the sass files being compiled. They may take zero or more input parameters and must return a value either synchronously (`return ...;`) or asynchronously (`done();`). Those parameters will be instances of one of the constructors contained in the `require('node-sass').types` hash. The return value must be of one of these types as well. See the list of available types below: `functions` is an `Object` that holds a collection of custom functions that may be invoked by the sass files being compiled. They may take zero or more input parameters and must return a value either synchronously (`return ...;`) or asynchronously (`done();`). Those parameters will be instances of one of the constructors contained in the `require('node-sass').types` hash. The return value must be of one of these types as well. See the list of available types below:
#### types.Number(value [, unit = ""]) #### types.Number(value [, unit = ""])
...@@ -163,6 +163,25 @@ Default: `false` ...@@ -163,6 +163,25 @@ Default: `false`
`true` values enable [Sass Indented Syntax](http://sass-lang.com/documentation/file.INDENTED_SYNTAX.html) for parsing the data string or file. `true` values enable [Sass Indented Syntax](http://sass-lang.com/documentation/file.INDENTED_SYNTAX.html) for parsing the data string or file.
### indentType (>= v3.0.0)
Type: `String`
Default: `space`
Used to determine whether to use space or tab character for indentation.
### indentWidth (>= v3.0.0)
Type: `Number`
Default: `2`
Maximum: `10`
Used to determine the number of spaces or tabs to be used for indentation.
### linefeed (>= v3.0.0)
Type: `String`
Default: `lf`
Used to determine whether to use `cr`, `crlf`, `lf` or `lfcr` sequence for line break.
### omitSourceMapUrl ### omitSourceMapUrl
Type: `Boolean` Type: `Boolean`
Default: `false` Default: `false`
...@@ -404,7 +423,8 @@ The interface for command-line usage is fairly simplistic at this stage, as seen ...@@ -404,7 +423,8 @@ The interface for command-line usage is fairly simplistic at this stage, as seen
Output will be saved with the same name as input SASS file into the current working directory if it's omitted. Output will be saved with the same name as input SASS file into the current working directory if it's omitted.
### Usage ### Usage
`node-sass [options] <input.scss> [<output.css>]` `node-sass [options] <input.scss> [output.css]`
`cat <input.scss> | node-sass > output.css`
**Options:** **Options:**
...@@ -415,7 +435,10 @@ Output will be saved with the same name as input SASS file into the current work ...@@ -415,7 +435,10 @@ Output will be saved with the same name as input SASS file into the current work
-x, --omit-source-map-url Omit source map URL comment from output -x, --omit-source-map-url Omit source map URL comment from output
-i, --indented-syntax Treat data from stdin as sass code (versus scss) -i, --indented-syntax Treat data from stdin as sass code (versus scss)
-v, --version Prints version info -v, --version Prints version info
--output-style CSS output style (nested|expanded|compact|compressed) --output-style CSS output style (nested | expanded | compact | compressed)
--indent-type Indent type for output CSS (space | tab)
--indent-width Indent width; number of spaces or tabs (maximum value: 10)
--linefeed Linefeed style (cr | crlf | lf | lfcr)
--source-comments Include debug info in output --source-comments Include debug info in output
--source-map Emit source map --source-map Emit source map
--source-map-embed Embed sourceMappingUrl as data URI --source-map-embed Embed sourceMappingUrl as data URI
......
...@@ -31,7 +31,10 @@ var cli = meow({ ...@@ -31,7 +31,10 @@ var cli = meow({
' -x, --omit-source-map-url Omit source map URL comment from output', ' -x, --omit-source-map-url Omit source map URL comment from output',
' -i, --indented-syntax Treat data from stdin as sass code (versus scss)', ' -i, --indented-syntax Treat data from stdin as sass code (versus scss)',
' -v, --version Prints version info', ' -v, --version Prints version info',
' --output-style CSS output style (nested|expanded|compact|compressed)', ' --output-style CSS output style (nested | expanded | compact | compressed)',
' --indent-type Indent type for output CSS (space | tab)',
' --indent-width Indent width; number of spaces or tabs (maximum value: 10)',
' --linefeed Linefeed style (cr | crlf | lf | lfcr)',
' --source-comments Include debug info in output', ' --source-comments Include debug info in output',
' --source-map Emit source map', ' --source-map Emit source map',
' --source-map-embed Embed sourceMappingUrl as data URI', ' --source-map-embed Embed sourceMappingUrl as data URI',
...@@ -52,6 +55,8 @@ var cli = meow({ ...@@ -52,6 +55,8 @@ var cli = meow({
], ],
string: [ string: [
'include-path', 'include-path',
'indent-type',
'linefeed',
'output', 'output',
'output-style', 'output-style',
'precision', 'precision',
...@@ -68,6 +73,9 @@ var cli = meow({ ...@@ -68,6 +73,9 @@ var cli = meow({
}, },
default: { default: {
'include-path': process.cwd(), 'include-path': process.cwd(),
'indent-type': 'space',
'indent-width': 2,
linefeed: 'lf',
'output-style': 'nested', 'output-style': 'nested',
precision: 5 precision: 5
} }
......
...@@ -97,7 +97,6 @@ function endStats(stats) { ...@@ -97,7 +97,6 @@ function endStats(stats) {
*/ */
function getStyle(options) { function getStyle(options) {
var style = options.outputStyle;
var styles = { var styles = {
nested: 0, nested: 0,
expanded: 1, expanded: 1,
...@@ -105,7 +104,54 @@ function getStyle(options) { ...@@ -105,7 +104,54 @@ function getStyle(options) {
compressed: 3 compressed: 3
}; };
return styles[style]; return styles[options.outputStyle] || 0;
}
/**
* Get indent width
*
* @param {Object} options
* @api private
*/
function getIndentWidth(options) {
var width = parseInt(options.indentWidth) || 2;
return width > 10 ? 2 : width;
}
/**
* Get indent type
*
* @param {Object} options
* @api private
*/
function getIndentType(options) {
var types = {
space: 0,
tab: 1
};
return types[options.indentType] || 0;
}
/**
* Get linefeed
*
* @param {Object} options
* @api private
*/
function getLinefeed(options) {
var feeds = {
cr: '\r',
crlf: '\r\n',
lf: '\n',
lfcr: '\n\r'
};
return feeds[options.linefeed] || '\n';
} }
/** /**
...@@ -124,7 +170,10 @@ function getOptions(options, cb) { ...@@ -124,7 +170,10 @@ function getOptions(options, cb) {
options.includePaths = (options.includePaths || []).join(path.delimiter); options.includePaths = (options.includePaths || []).join(path.delimiter);
options.precision = parseInt(options.precision) || 5; options.precision = parseInt(options.precision) || 5;
options.sourceMap = getSourceMap(options); options.sourceMap = getSourceMap(options);
options.style = getStyle(options) || 0; options.style = getStyle(options);
options.indentWidth = getIndentWidth(options);
options.indentType = getIndentType(options);
options.linefeed = getLinefeed(options);
// context object represents node-sass environment // context object represents node-sass environment
options.context = { options: options, callback: cb }; options.context = { options: options, callback: cb };
......
...@@ -28,8 +28,11 @@ module.exports = function(options, emitter) { ...@@ -28,8 +28,11 @@ module.exports = function(options, emitter) {
sourceMapEmbed: options.sourceMapEmbed, sourceMapEmbed: options.sourceMapEmbed,
sourceMapContents: options.sourceMapContents, sourceMapContents: options.sourceMapContents,
sourceMap: options.sourceMap, sourceMap: options.sourceMap,
importer: options.importer importer: options.importer,
}; indentWidth: options.indentWidth,
indentType: options.indentType,
linefeed: options.linefeed
};
if (options.data) { if (options.data) {
renderOptions.data = options.data; renderOptions.data = options.data;
......
...@@ -11,8 +11,8 @@ struct Sass_Import** sass_importer(const char* file, const char* prev, void* coo ...@@ -11,8 +11,8 @@ struct Sass_Import** sass_importer(const char* file, const char* prev, void* coo
CustomImporterBridge& bridge = *(ctx_w->importer_bridge); CustomImporterBridge& bridge = *(ctx_w->importer_bridge);
std::vector<void*> argv; std::vector<void*> argv;
argv.push_back((void*) file); argv.push_back((void*)file);
argv.push_back((void*) prev); argv.push_back((void*)prev);
return bridge(argv); return bridge(argv);
} }
...@@ -23,12 +23,13 @@ union Sass_Value* sass_custom_function(const union Sass_Value* s_args, void* coo ...@@ -23,12 +23,13 @@ union Sass_Value* sass_custom_function(const union Sass_Value* s_args, void* coo
std::vector<void*> argv; std::vector<void*> argv;
for (unsigned l = sass_list_get_length(s_args), i = 0; i < l; i++) { for (unsigned l = sass_list_get_length(s_args), i = 0; i < l; i++) {
argv.push_back((void*) sass_list_get_value(s_args, i)); argv.push_back((void*)sass_list_get_value(s_args, i));
} }
try { try {
return bridge(argv); return bridge(argv);
} catch (const std::exception& e) { }
catch (const std::exception& e) {
return sass_make_error(e.what()); return sass_make_error(e.what());
} }
} }
...@@ -72,19 +73,36 @@ void ExtractOptions(Local<Object> options, void* cptr, sass_context_wrapper* ctx ...@@ -72,19 +73,36 @@ void ExtractOptions(Local<Object> options, void* cptr, sass_context_wrapper* ctx
} }
if (!is_file) { if (!is_file) {
sass_option_set_input_path(sass_options, create_string(options->Get(NanNew("file")))); ctx_w->file = create_string(options->Get(NanNew("file")));
sass_option_set_input_path(sass_options, ctx_w->file);
} }
sass_option_set_output_path(sass_options, create_string(options->Get(NanNew("outFile")))); int indent_len = options->Get(NanNew("indentWidth"))->Int32Value();
ctx_w->indent = (char*)malloc(indent_len + 1);
strcpy(ctx_w->indent, std::string(
indent_len,
options->Get(NanNew("indentType"))->Int32Value() == 1 ? '\t' : ' '
).c_str());
ctx_w->linefeed = create_string(options->Get(NanNew("linefeed")));
ctx_w->include_path = create_string(options->Get(NanNew("includePaths")));
ctx_w->out_file = create_string(options->Get(NanNew("outFile")));
ctx_w->source_map = create_string(options->Get(NanNew("sourceMap")));
sass_option_set_output_path(sass_options, ctx_w->out_file);
sass_option_set_output_style(sass_options, (Sass_Output_Style)options->Get(NanNew("style"))->Int32Value()); sass_option_set_output_style(sass_options, (Sass_Output_Style)options->Get(NanNew("style"))->Int32Value());
sass_option_set_is_indented_syntax_src(sass_options, options->Get(NanNew("indentedSyntax"))->BooleanValue()); sass_option_set_is_indented_syntax_src(sass_options, options->Get(NanNew("indentedSyntax"))->BooleanValue());
sass_option_set_source_comments(sass_options, options->Get(NanNew("sourceComments"))->BooleanValue()); sass_option_set_source_comments(sass_options, options->Get(NanNew("sourceComments"))->BooleanValue());
sass_option_set_omit_source_map_url(sass_options, options->Get(NanNew("omitSourceMapUrl"))->BooleanValue()); sass_option_set_omit_source_map_url(sass_options, options->Get(NanNew("omitSourceMapUrl"))->BooleanValue());
sass_option_set_source_map_embed(sass_options, options->Get(NanNew("sourceMapEmbed"))->BooleanValue()); sass_option_set_source_map_embed(sass_options, options->Get(NanNew("sourceMapEmbed"))->BooleanValue());
sass_option_set_source_map_contents(sass_options, options->Get(NanNew("sourceMapContents"))->BooleanValue()); sass_option_set_source_map_contents(sass_options, options->Get(NanNew("sourceMapContents"))->BooleanValue());
sass_option_set_source_map_file(sass_options, create_string(options->Get(NanNew("sourceMap")))); sass_option_set_source_map_file(sass_options, ctx_w->source_map);
sass_option_set_include_path(sass_options, create_string(options->Get(NanNew("includePaths")))); sass_option_set_include_path(sass_options, ctx_w->include_path);
sass_option_set_precision(sass_options, options->Get(NanNew("precision"))->Int32Value()); sass_option_set_precision(sass_options, options->Get(NanNew("precision"))->Int32Value());
sass_option_set_indent(sass_options, ctx_w->indent);
sass_option_set_linefeed(sass_options, ctx_w->linefeed);
Local<Object> custom_functions = Local<Object>::Cast(options->Get(NanNew("functions"))); Local<Object> custom_functions = Local<Object>::Cast(options->Get(NanNew("functions")));
......
...@@ -39,7 +39,13 @@ extern "C" { ...@@ -39,7 +39,13 @@ extern "C" {
NanDisposePersistent(ctx_w->result); NanDisposePersistent(ctx_w->result);
if(string) { free(ctx_w->include_path);
free(ctx_w->linefeed);
free(ctx_w->out_file);
free(ctx_w->source_map);
free(ctx_w->indent);
if (string) {
free(string); free(string);
} }
......
...@@ -23,6 +23,12 @@ extern "C" { ...@@ -23,6 +23,12 @@ extern "C" {
// binding related // binding related
bool is_sync; bool is_sync;
void* cookie; void* cookie;
char* file;
char* include_path;
char* out_file;
char* source_map;
char* linefeed;
char* indent;
// libsass related // libsass related
Sass_Data_Context* dctx; Sass_Data_Context* dctx;
......
...@@ -103,7 +103,7 @@ describe('api', function() { ...@@ -103,7 +103,7 @@ describe('api', function() {
}); });
}); });
it('should render with --precision option', function(done) { it('should render with precision option', function(done) {
var src = read(fixture('precision/index.scss'), 'utf8'); var src = read(fixture('precision/index.scss'), 'utf8');
var expected = read(fixture('precision/expected.css'), 'utf8').trim(); var expected = read(fixture('precision/expected.css'), 'utf8').trim();
...@@ -131,6 +131,27 @@ describe('api', function() { ...@@ -131,6 +131,27 @@ describe('api', function() {
done(); done();
}); });
}); });
it('should render with indentWidth and indentType options', function(done) {
sass.render({
data: 'div { color: transparent; }',
indentWidth: 7,
indentType: 'tab'
}, function(error, result) {
assert.equal(result.css.toString().trim(), 'div {\n\t\t\t\t\t\t\tcolor: transparent; }');
done();
});
});
it('should render with linefeed option', function(done) {
sass.render({
data: 'div { color: transparent; }',
linefeed: 'lfcr'
}, function(error, result) {
assert.equal(result.css.toString().trim(), 'div {\n\r color: transparent; }');
done();
});
});
}); });
describe('.render(importer)', function() { describe('.render(importer)', function() {
......
...@@ -2,6 +2,7 @@ var assert = require('assert'), ...@@ -2,6 +2,7 @@ var assert = require('assert'),
fs = require('fs'), fs = require('fs'),
path = require('path'), path = require('path'),
read = require('fs').readFileSync, read = require('fs').readFileSync,
stream = require('stream'),
spawn = require('cross-spawn'), spawn = require('cross-spawn'),
cli = path.join(__dirname, '..', 'bin', 'node-sass'), cli = path.join(__dirname, '..', 'bin', 'node-sass'),
fixture = path.join.bind(null, __dirname, 'fixtures'); fixture = path.join.bind(null, __dirname, 'fixtures');
...@@ -63,6 +64,40 @@ describe('cli', function() { ...@@ -63,6 +64,40 @@ describe('cli', function() {
src.pipe(bin.stdin); src.pipe(bin.stdin);
}); });
it('should render with indentWidth and indentType options', function(done) {
var src = new stream.Readable();
var bin = spawn(cli, ['--indent-width', 7, '--indent-type', 'tab']);
src._read = function() { };
src.push('div { color: transparent; }');
src.push(null);
bin.stdout.setEncoding('utf8');
bin.stdout.once('data', function(data) {
assert.equal(data.trim(), 'div {\n\t\t\t\t\t\t\tcolor: transparent; }');
done();
});
src.pipe(bin.stdin);
});
it('should render with linefeed option', function(done) {
var src = new stream.Readable();
var bin = spawn(cli, ['--linefeed', 'lfcr']);
src._read = function() { };
src.push('div { color: transparent; }');
src.push(null);
bin.stdout.setEncoding('utf8');
bin.stdout.once('data', function(data) {
assert.equal(data.trim(), 'div {\n\r color: transparent; }');
done();
});
src.pipe(bin.stdin);
});
}); });
describe('node-sass in.scss', function() { describe('node-sass in.scss', function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment