diff --git a/bin/node-sass b/bin/node-sass index d19d9a961..2502515d8 100755 --- a/bin/node-sass +++ b/bin/node-sass @@ -5,7 +5,8 @@ var Emitter = require('events').EventEmitter, meow = require('meow'), replaceExt = require('replace-ext'), stdin = require('get-stdin'), - render = require('../lib/render'); + render = require('../lib/render'), + fs = require('fs'); /** * Initialize CLI @@ -14,6 +15,8 @@ var Emitter = require('events').EventEmitter, var cli = meow({ pkg: '../package.json', help: [ + require('../lib/').info(), + '', 'Usage', ' node-sass [options] [output.css]', ' cat | node-sass > output.css', @@ -37,6 +40,7 @@ var cli = meow({ ' --image-path Path to prepend when using the `image-url()` helper', ' --precision The amount of precision allowed in decimal numbers', ' --stdout Print the resulting CSS to stdout', + ' --importer Path to custom importer', ' --help Print usage info' ].join('\n') }, { @@ -105,6 +109,10 @@ function getEmitter() { console.log(data); }); + emitter.on('done', function(){ + process.exit(0); + }); + return emitter; } @@ -202,6 +210,15 @@ function run(options, emitter) { } } + if (options.importer) { + if (fs.existsSync(options.importer)) { + options.importer = require(options.importer); + } else { + console.error('Could not locate importer.'); + process.exit(1); + } + } + if (options.watch) { watch(options, emitter); } else { @@ -240,6 +257,7 @@ if (options.src) { } else if (!process.stdin.isTTY) { stdin(function(data) { options.data = data; + options.stdin = true; run(options, emitter); }); } diff --git a/lib/index.js b/lib/index.js index 12e6f05b7..ccfe9a168 100644 --- a/lib/index.js +++ b/lib/index.js @@ -54,7 +54,7 @@ function getOutFile(options) { */ function getStats(options) { - var stats = options.stats; + var stats = {}; stats.entry = options.file || 'data'; stats.start = Date.now(); @@ -65,17 +65,14 @@ function getStats(options) { /** * End stats * - * @param {Object} options + * @param {Object} stats * @param {Object} sourceMap * @api private */ -function endStats(options, sourceMap) { - var stats = options.stats || {}; - +function endStats(stats) { stats.end = Date.now(); stats.duration = stats.end - stats.start; - stats.sourceMap = sourceMap; return stats; } @@ -139,15 +136,12 @@ function getOptions(options) { options.paths = (options.include_paths || options.includePaths || []).join(path.delimiter); options.precision = parseInt(options.precision) || 5; options.sourceMap = getSourceMap(options); - options.stats = options.stats || {}; options.style = getStyle(options) || 0; if (options.imagePath && typeof options.imagePath !== 'string') { throw new Error('`imagePath` needs to be a string'); } - getStats(options); - var error = options.error; var success = options.success; var importer = options.importer; @@ -159,29 +153,41 @@ function getOptions(options) { err = { message: err }; } + err.code = code; + if (error) { - error(err, code); + error(err); } }; - options.success = function(css, sourceMap) { - sourceMap = JSON.parse(sourceMap); + options.success = function() { + options.result.sourceMap = JSON.parse(options.result.sourceMap); - endStats(options, sourceMap); + var stats = endStats(options.result.stats); if (success) { - success(css, sourceMap); + success({ + css: options.result.css, + map: options.result.sourceMap, + stats: stats + }); } }; if (importer) { options.importer = function(file, prev, key) { - importer(file, prev, function(data) { + var done = function(data) { binding.importedCallback({ index: key, objectLiteral: data }); - }); + }; + + var result = importer(file, prev, done); + + if (result) { + done(result); + } }; } @@ -191,6 +197,10 @@ function getOptions(options) { delete options.source_comments; delete options.sourceComments; + options.result = { + stats: getStats(options) + }; + return options; } @@ -200,41 +210,6 @@ function getOptions(options) { var binding = require(getBinding()); -/** - * Render (deprecated) - * - * @param {String} css - * @param {Function} cb - * @param {Object} options - * @api private - */ - -function deprecatedRender(css, cb, options) { - options = getOptions(options); - options.data = css; - options.error = cb; - options.success = function(css) { - cb(null, css); - }; - - binding.render(options); -} - -/** - * Render sync (deprecated) - * - * @param {String} css - * @param {Object} options - * @api private - */ - -function deprecatedRenderSync(css, options) { - options = getOptions(options); - options.data = css; - - return binding.renderSync(options); -} - /** * Render * @@ -243,12 +218,9 @@ function deprecatedRenderSync(css, options) { */ module.exports.render = function(options) { - if (typeof arguments[0] === 'string') { - return deprecatedRender.apply(this, arguments); - } - options = getOptions(options); - options.file ? binding.renderFile(options) : binding.render(options); + + options.data ? binding.render(options) : binding.renderFile(options); }; /** @@ -259,79 +231,27 @@ module.exports.render = function(options) { */ module.exports.renderSync = function(options) { - if (typeof arguments[0] === 'string') { - return deprecatedRenderSync.apply(this, arguments); - } - - var output; - options = getOptions(options); - output = options.file ? binding.renderFileSync(options) : binding.renderSync(options); - - endStats(options, JSON.parse(options.stats.sourceMap)); - return output; -}; -/** - * Render file - * - * `options.sourceMap` can be used to specify that the source map should be saved: - * - * - If falsy the source map will not be saved - * - If `options.sourceMap === true` the source map will be saved to the - * standard location of `options.file + '.map'` - * - Else `options.sourceMap` specifies the path (relative to the `outFile`) - * where the source map should be saved - * - * @param {Object} options - * @api public - */ + var result = options.data ? binding.renderSync(options) : binding.renderFileSync(options); -module.exports.renderFile = function(options) { - options = options || {}; + if(result) { + options.result.stats = endStats(options.result.stats); - var outFile = options.outFile; - var success = options.success; - - if (options.sourceMap === true) { - options.sourceMap = outFile + '.map'; + return options.result; } - - options.success = function(css, sourceMap) { - fs.writeFile(outFile, css, function(err) { - if (err) { - return options.error(err); - } - - if (!options.sourceMap) { - return success(outFile); - } - - var dir = path.dirname(outFile); - var sourceMapFile = path.resolve(dir, options.sourceMap); - - fs.writeFile(sourceMapFile, JSON.stringify(sourceMap), function(err) { - if (err) { - return options.error(err); - } - - success(outFile, sourceMapFile); - }); - }); - }; - - module.exports.render(options); }; /** - * Middleware + * API Info * - * @api public */ -module.exports.middleware = function() { - return new Error([ - 'The middleware has been moved to', - 'https://github.com/sass/node-sass-middleware' - ].join(' ')); +module.exports.info = function() { + var package = require('../package.json'); + + return [ + 'node-sass version: ' + package.version, + 'libsass version: ' + package.libsass + ].join('\n'); }; diff --git a/lib/render.js b/lib/render.js index 3c6e95d05..045301d3d 100644 --- a/lib/render.js +++ b/lib/render.js @@ -22,7 +22,8 @@ module.exports = function(options, emitter) { sourceComments: options.sourceComments, sourceMapEmbed: options.sourceMapEmbed, sourceMapContents: options.sourceMapContents, - sourceMap: options.sourceMap + sourceMap: options.sourceMap, + importer: options.importer }; if (options.src) { @@ -31,7 +32,7 @@ module.exports = function(options, emitter) { renderOptions.data = options.data; } - renderOptions.success = function(css, sourceMap) { + renderOptions.success = function(result) { var todo = 1; var done = function() { if (--todo <= 0) { @@ -39,38 +40,38 @@ module.exports = function(options, emitter) { } }; - if (options.stdout || (!options.dest && !process.stdout.isTTY)) { - emitter.emit('log', css); + if (options.stdout || (!options.dest && !process.stdout.isTTY) || options.stdin) { + emitter.emit('log', result.css); return done(); } emitter.emit('warn', chalk.green('Rendering Complete, saving .css file...')); - fs.writeFile(options.dest, css, function(err) { + fs.writeFile(options.dest, result.css, function(err) { if (err) { return emitter.emit('error', chalk.red(err)); } emitter.emit('warn', chalk.green('Wrote CSS to ' + options.dest)); - emitter.emit('write', err, options.dest, css); + emitter.emit('write', err, options.dest, result.css); done(); }); if (options.sourceMap) { todo++; - fs.writeFile(options.sourceMap, sourceMap, function(err) { + fs.writeFile(options.sourceMap, result.map, function(err) { if (err) { return emitter.emit('error', chalk.red('Error' + err)); } emitter.emit('warn', chalk.green('Wrote Source Map to ' + options.sourceMap)); - emitter.emit('write-source-map', err, options.sourceMap, sourceMap); + emitter.emit('write-source-map', err, options.sourceMap, result.sourceMap); done(); }); } - emitter.emit('render', css); + emitter.emit('render', result.css); }; renderOptions.error = function(error) { diff --git a/package.json b/package.json index 93a333497..a906ea0f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "node-sass", - "version": "1.2.3", + "version": "2.0.0-beta", + "libsass": "3.1.0-beta", "description": "Wrapper around libsass", "license": "MIT", "homepage": "https://github.com/sass/node-sass", @@ -50,7 +51,7 @@ "mkdirp": "^0.5.0", "mocha": "^2.0.1", "nan": "^1.3.0", - "object-assign": "^1.0.0", + "object-assign": "^2.0.0", "replace-ext": "0.0.1", "request": "^2.48.0", "shelljs": "^0.3.0" diff --git a/src/binding.cpp b/src/binding.cpp index 417dcc6f7..3da17ca06 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -15,7 +15,7 @@ char* CreateString(Local value) { std::vector imports_collection; -void dispatched_async_uv_callback(uv_async_t *req){ +void dispatched_async_uv_callback(uv_async_t *req) { NanScope(); sass_context_wrapper* ctx_w = static_cast(req->data); @@ -24,8 +24,8 @@ void dispatched_async_uv_callback(uv_async_t *req){ imports_collection.push_back(ctx_w); Handle argv[] = { - NanNew(strdup(ctx_w->file)), - NanNew(strdup(ctx_w->prev)), + NanNew(strdup(ctx_w->file ? ctx_w->file : 0)), + NanNew(strdup(ctx_w->prev ? ctx_w->prev : 0)), NanNew(imports_collection.size() - 1) }; @@ -40,8 +40,8 @@ struct Sass_Import** sass_importer(const char* file, const char* prev, void* coo { sass_context_wrapper* ctx_w = static_cast(cookie); - ctx_w->file = strdup(file); - ctx_w->prev = strdup(prev); + ctx_w->file = file ? strdup(file) : 0; + ctx_w->prev = prev ? strdup(prev) : 0; ctx_w->async.data = (void*)ctx_w; uv_async_send(&ctx_w->async); @@ -52,7 +52,7 @@ struct Sass_Import** sass_importer(const char* file, const char* prev, void* coo */ uv_cond_wait(&ctx_w->importer_condition_variable, &ctx_w->importer_mutex); } - else{ + else { /* that is sync: RenderSync() or RenderFileSync, * we need to explicitly uv_run as the event loop * is blocked; waiting down the chain. @@ -66,6 +66,8 @@ struct Sass_Import** sass_importer(const char* file, const char* prev, void* coo void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx_w, bool isFile, bool isSync) { struct Sass_Context* ctx; + NanAssignPersistent(ctx_w->result, options->Get(NanNew("result"))->ToObject()); + if (isFile) { ctx = sass_file_context_get_context((struct Sass_File_Context*) cptr); ctx_w->fctx = (struct Sass_File_Context*) cptr; @@ -78,8 +80,6 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx struct Sass_Options* sass_options = sass_context_get_options(ctx); if (!isSync) { - NanAssignPersistent(ctx_w->stats, options->Get(NanNew("stats"))->ToObject()); - ctx_w->request.data = ctx_w; // async (callback) style @@ -99,6 +99,7 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w)); } + sass_option_set_input_path(sass_options, CreateString(options->Get(NanNew("file")))); sass_option_set_output_path(sass_options, CreateString(options->Get(NanNew("outFile")))); sass_option_set_image_path(sass_options, CreateString(options->Get(NanNew("imagePath")))); sass_option_set_output_style(sass_options, (Sass_Output_Style)options->Get(NanNew("style"))->Int32Value()); @@ -112,7 +113,7 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx sass_option_set_precision(sass_options, options->Get(NanNew("precision"))->Int32Value()); } -void FillStatsObj(Handle stats, Sass_Context* ctx) { +void GetStats(Handle result, Sass_Context* ctx) { char** included_files = sass_context_get_included_files(ctx); Handle arr = NanNew(); @@ -122,8 +123,10 @@ void FillStatsObj(Handle stats, Sass_Context* ctx) { } } - (*stats)->Set(NanNew("includedFiles"), arr); + (*result)->Get(NanNew("stats"))->ToObject()->Set(NanNew("includedFiles"), arr); +} +void GetSourceMap(Handle result, Sass_Context* ctx) { Handle source_map; if (sass_context_get_error_status(ctx)) { @@ -137,7 +140,19 @@ void FillStatsObj(Handle stats, Sass_Context* ctx) { source_map = NanNew("{}"); } - (*stats)->Set(NanNew("sourceMap"), source_map); + (*result)->Set(NanNew("sourceMap"), source_map); +} + +int GetResult(Handle result, Sass_Context* ctx) { + int status = sass_context_get_error_status(ctx); + + if (status == 0) { + (*result)->Set(NanNew("css"), NanNew(sass_context_get_output_string(ctx))); + GetStats(result, ctx); + GetSourceMap(result, ctx); + } + + return status; } void make_callback(uv_work_t* req) { @@ -145,35 +160,27 @@ void make_callback(uv_work_t* req) { TryCatch try_catch; sass_context_wrapper* ctx_w = static_cast(req->data); - int error_status; struct Sass_Context* ctx; if (ctx_w->dctx) { ctx = sass_data_context_get_context(ctx_w->dctx); - FillStatsObj(NanNew(ctx_w->stats), ctx); - error_status = sass_context_get_error_status(ctx); } else { ctx = sass_file_context_get_context(ctx_w->fctx); - FillStatsObj(NanNew(ctx_w->stats), ctx); - error_status = sass_context_get_error_status(ctx); } - if (error_status == 0) { + int status = GetResult(ctx_w->result, ctx); + + if (status == 0) { // if no error, do callback(null, result) - const char* val = sass_context_get_output_string(ctx); - Local argv[] = { - NanNew(val), - NanNew(ctx_w->stats)->Get(NanNew("sourceMap")) - }; - ctx_w->success_callback->Call(2, argv); + ctx_w->success_callback->Call(0, 0); } else { // if error, do callback(error) const char* err = sass_context_get_error_json(ctx); Local argv[] = { NanNew(err), - NanNew(error_status) + NanNew(status) }; ctx_w->error_callback->Call(2, argv); } @@ -212,21 +219,22 @@ NAN_METHOD(RenderSync) { ExtractOptions(options, dctx, ctx_w, false, true); compile_data(dctx); - FillStatsObj(options->Get(NanNew("stats"))->ToObject(), ctx); - if (sass_context_get_error_status(ctx) == 0) { - Local output = NanNew(sass_context_get_output_string(ctx)); + int result = GetResult(ctx_w->result, ctx); + Local error; - sass_delete_data_context(dctx); - NanReturnValue(output); + if (result != 0) { + error = NanNew(sass_context_get_error_json(ctx)); } - Local error = NanNew(sass_context_get_error_json(ctx)); - sass_free_context_wrapper(ctx_w); - NanThrowError(error); + free(source_string); - NanReturnUndefined(); + if (result != 0) { + NanThrowError(error); + } + + NanReturnValue(NanNew(result == 0)); } NAN_METHOD(RenderFile) { @@ -258,22 +266,22 @@ NAN_METHOD(RenderFileSync) { ExtractOptions(options, fctx, ctx_w, true, true); compile_file(fctx); - FillStatsObj(options->Get(NanNew("stats"))->ToObject(), ctx); - free(input_path); - if (sass_context_get_error_status(ctx) == 0) { - Local output = NanNew(sass_context_get_output_string(ctx)); + int result = GetResult(ctx_w->result, ctx); + Local error; - sass_delete_file_context(fctx); - NanReturnValue(output); + if (result != 0) { + error = NanNew(sass_context_get_error_json(ctx)); } - Local error = NanNew(sass_context_get_error_json(ctx)); - sass_free_context_wrapper(ctx_w); - NanThrowError(error); + free(input_path); - NanReturnUndefined(); + if (result != 0) { + NanThrowError(error); + } + + NanReturnValue(NanNew(result == 0)); } NAN_METHOD(ImportedCallback) { @@ -282,9 +290,7 @@ NAN_METHOD(ImportedCallback) { TryCatch try_catch; Local options = args[0]->ToObject(); - char* source_string = CreateString(options->Get(NanNew("index"))); Local returned_value = options->Get(NanNew("objectLiteral")); - size_t index = options->Get(NanNew("index"))->Int32Value(); if (index >= imports_collection.size()) { diff --git a/src/libsass b/src/libsass index 7aaa45a97..cf7c1d14f 160000 --- a/src/libsass +++ b/src/libsass @@ -1 +1 @@ -Subproject commit 7aaa45a979ce65d50b3158ff50bf9409f8955063 +Subproject commit cf7c1d14fec91a66ab9c2a3050dcec5fab6198f5 diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index 35023e1b1..cba991641 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -37,14 +37,13 @@ extern "C" { sass_delete_file_context(ctx_w->fctx); } - NanDisposePersistent(ctx_w->stats); + NanDisposePersistent(ctx_w->result); delete ctx_w->success_callback; delete ctx_w->error_callback; delete ctx_w->importer_callback; delete ctx_w->file; delete ctx_w->prev; - delete ctx_w->cookie; uv_mutex_destroy(&ctx_w->importer_mutex); uv_cond_destroy(&ctx_w->importer_condition_variable); diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index 902a70df1..53659c571 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -14,7 +14,7 @@ extern "C" { struct sass_context_wrapper { Sass_Data_Context* dctx; Sass_File_Context* fctx; - Persistent stats; + Persistent result; uv_work_t request; uv_mutex_t importer_mutex; uv_cond_t importer_condition_variable; diff --git a/test/api.js b/test/api.js index 4959b7dfe..2fa786cb9 100644 --- a/test/api.js +++ b/test/api.js @@ -6,79 +6,28 @@ var assert = require('assert'), fixture = path.join.bind(null, __dirname, 'fixtures'), resolveFixture = path.resolve.bind(null, __dirname, 'fixtures'); -describe('api (deprecated)', function() { - describe('.render(src, fn)', function() { - it('should compile sass to css', function(done) { - var src = read(fixture('simple/index.scss'), 'utf8'); - var expected = read(fixture('simple/expected.css'), 'utf8').trim(); - - sass.render(src, function(err, css) { - assert(!err); - assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); - done(); - }); - }); - - it('should compile sass to css using indented syntax', function(done) { - var src = read(fixture('indent/index.sass'), 'utf8'); - var expected = read(fixture('indent/expected.css'), 'utf8').trim(); - - sass.render(src, function(err, css) { - assert(!err); - assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); - done(); - }, { - indentedSyntax: true - }); - }); - - it('should throw error for bad input', function(done) { - sass.render('#navbar width 80%;', function(err) { - assert(err); - done(); - }); - }); - }); - - describe('.renderSync(src)', function() { - it('should compile sass to css', function(done) { - var src = read(fixture('simple/index.scss'), 'utf8'); +describe('api', function() { + describe('.render(options)', function() { + it('should compile sass to css with file', function(done) { var expected = read(fixture('simple/expected.css'), 'utf8').trim(); - var css = sass.renderSync(src).trim(); - - assert.equal(css, expected.replace(/\r\n/g, '\n')); - done(); - }); - - it('should compile sass to css using indented syntax', function(done) { - var src = read(fixture('indent/index.sass'), 'utf8'); - var expected = read(fixture('indent/expected.css'), 'utf8').trim(); - var css = sass.renderSync(src, {indentedSyntax: true}).trim(); - assert.equal(css, expected.replace(/\r\n/g, '\n')); - done(); - }); - - it('should throw error for bad input', function(done) { - assert.throws(function() { - sass.renderSync('#navbar width 80%;'); + sass.render({ + file: fixture('simple/index.scss'), + success: function(result) { + assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n')); + done(); + } }); - - done(); }); - }); -}); -describe('api', function() { - describe('.render(options)', function() { - it('should compile sass to css', function(done) { + it('should compile sass to css with data', function(done) { var src = read(fixture('simple/index.scss'), 'utf8'); var expected = read(fixture('simple/expected.css'), 'utf8').trim(); sass.render({ data: src, - success: function(css) { - assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); + success: function(result) { + assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n')); done(); } }); @@ -91,8 +40,8 @@ describe('api', function() { sass.render({ data: src, indentedSyntax: true, - success: function(css) { - assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); + success: function(result) { + assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n')); done(); } }); @@ -101,9 +50,9 @@ describe('api', function() { it('should throw error status 1 for bad input', function(done) { sass.render({ data: '#navbar width 80%;', - error: function(err, status) { - assert(err); - assert.equal(status, 1); + error: function(error) { + assert(error.message); + assert.equal(error.status, 1); done(); } }); @@ -119,8 +68,8 @@ describe('api', function() { fixture('include-path/functions'), fixture('include-path/lib') ], - success: function(css) { - assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); + success: function(result) { + assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n')); done(); } }); @@ -133,8 +82,8 @@ describe('api', function() { sass.render({ data: src, imagePath: '/path/to/images', - success: function(css) { - assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); + success: function(result) { + assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n')); done(); } }); @@ -160,55 +109,234 @@ describe('api', function() { sass.render({ data: src, precision: 10, - success: function(css) { - assert.equal(css.trim(), expected.replace(/\r\n/g, '\n')); + success: function(result) { + assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n')); done(); } }); }); - it('should compile with stats', function(done) { - var src = fixture('precision/index.scss'); - var stats = {}; + it('should contain all included files in stats when data is passed', function(done) { + var src = read(fixture('include-files/index.scss'), 'utf8'); + var expected = [ + fixture('include-files/bar.scss').replace(/\\/g, '/'), + fixture('include-files/foo.scss').replace(/\\/g, '/') + ]; sass.render({ - file: src, - stats: stats, - sourceMap: true, - success: function() { - assert.equal(stats.entry, src); + data: src, + includePaths: [fixture('include-files')], + success: function(result) { + assert.deepEqual(result.stats.includedFiles, expected); done(); } }); }); + }); - it('should contain all included files in stats when data is passed', function(done) { - var src = fixture('include-files/index.scss'); - var stats = {}; - var expected = [ - fixture('include-files/bar.scss').replace(/\\/g, '/'), - fixture('include-files/foo.scss').replace(/\\/g, '/') - ]; + describe('.render(importer)', function() { + var src = read(fixture('include-files/index.scss'), 'utf8'); + it('should override imports with "data" as input and fires callback with file and contents', function(done) { sass.render({ - data: read(src, 'utf8'), - includePaths: [fixture('include-files')], - stats: stats, - success: function() { - assert.deepEqual(stats.includedFiles, expected); + data: src, + success: function(result) { + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }, + importer: function(url, prev, done) { + done({ + file: '/some/other/path.scss', + contents: 'div {color: yellow;}' + }); + } + }); + }); + + it('should override imports with "file" as input and fires callback with file and contents', function(done) { + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }, + importer: function(url, prev, done) { + done({ + file: '/some/other/path.scss', + contents: 'div {color: yellow;}' + }); + } + }); + }); + + it('should override imports with "data" as input and returns file and contents', function(done) { + sass.render({ + data: src, + success: function(result) { + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }, + importer: function(url, prev) { + return { + file: prev + url, + contents: 'div {color: yellow;}' + }; + } + }); + }); + + it('should override imports with "file" as input and returns file and contents', function(done) { + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }, + importer: function(url, prev) { + return { + file: prev + url, + contents: 'div {color: yellow;}' + }; + } + }); + }); + + it('should override imports with "data" as input and fires callback with file', function(done) { + sass.render({ + data: src, + success: function(result) { + assert.equal(result.css.trim(), ''); + done(); + }, + importer: function(url, /* jshint unused:false */ prev, done) { + done({ + file: path.resolve(path.dirname(fixture('include-files/index.scss')), url + (path.extname(url) ? '' : '.scss')) + }); + } + }); + }); + + it('should override imports with "file" as input and fires callback with file', function(done) { + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert.equal(result.css.trim(), ''); + done(); + }, + importer: function(url, prev, done) { + done({ + file: path.resolve(path.dirname(prev), url + (path.extname(url) ? '' : '.scss')) + }); + } + }); + }); + + it('should override imports with "data" as input and returns file', function(done) { + sass.render({ + data: src, + success: function(result) { + assert.equal(result.css.trim(), ''); + done(); + }, + importer: function(url, /* jshint unused:false */ prev) { + return { + file: path.resolve(path.dirname(fixture('include-files/index.scss')), url + (path.extname(url) ? '' : '.scss')) + }; + } + }); + }); + + it('should override imports with "file" as input and returns file', function(done) { + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert.equal(result.css.trim(), ''); + done(); + }, + importer: function(url, prev) { + return { + file: path.resolve(path.dirname(prev), url + (path.extname(url) ? '' : '.scss')) + }; + } + }); + }); + + it('should override imports with "data" as input and fires callback with contents', function(done) { + sass.render({ + data: src, + success: function(result) { + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }, + importer: function(url, prev, done) { + done({ + contents: 'div {color: yellow;}' + }); + } + }); + }); + + it('should override imports with "file" as input and fires callback with contents', function(done) { + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }, + importer: function(url, prev, done) { + done({ + contents: 'div {color: yellow;}' + }); + } + }); + }); + + it('should override imports with "data" as input and returns contents', function(done) { + sass.render({ + data: src, + success: function(result) { + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }, + importer: function() { + return { + contents: 'div {color: yellow;}' + }; + } + }); + }); + + it('should override imports with "file" as input and returns contents', function(done) { + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); done(); + }, + importer: function() { + return { + contents: 'div {color: yellow;}' + }; } }); }); }); describe('.renderSync(options)', function() { - it('should compile sass to css', function(done) { + it('should compile sass to css with file', function(done) { + var expected = read(fixture('simple/expected.css'), 'utf8').trim(); + var result = sass.renderSync({file: fixture('simple/index.scss')}); + + assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n')); + done(); + }); + + it('should compile sass to css with data', function(done) { var src = read(fixture('simple/index.scss'), 'utf8'); var expected = read(fixture('simple/expected.css'), 'utf8').trim(); - var css = sass.renderSync({data: src}).trim(); + var result = sass.renderSync({data: src}); - assert.equal(css, expected.replace(/\r\n/g, '\n')); + assert.equal(result.css.trim(), expected.replace(/\r\n/g, '\n')); done(); }); @@ -218,7 +346,7 @@ describe('api', function() { var css = sass.renderSync({ data: src, indentedSyntax: true - }).trim(); + }).css.trim(); assert.equal(css, expected.replace(/\r\n/g, '\n')); done(); @@ -233,109 +361,191 @@ describe('api', function() { }); }); - describe('.renderFile(options)', function() { - it('should compile sass to css', function(done) { - var src = read(fixture('simple/index.scss'), 'utf8'); - var dest = fixture('simple/build.css'); - var expected = read(fixture('simple/expected.css'), 'utf8').trim(); + describe('.renderSync(importer)', function() { + var src = read(fixture('include-files/index.scss'), 'utf8'); - sass.renderFile({ + it('should override imports with "data" as input and fires callback with file and contents', function(done) { + var result = sass.renderSync({ data: src, - outFile: dest, - success: function() { - assert.equal(read(dest, 'utf8').trim(), expected.replace(/\r\n/g, '\n')); - fs.unlinkSync(dest); - done(); + importer: function(url, prev, done) { + done({ + file: '/some/other/path.scss', + contents: 'div {color: yellow;}' + }); } }); + + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); }); - it('should compile sass to css using indented syntax', function(done) { - var src = read(fixture('indent/index.sass'), 'utf8'); - var dest = fixture('indent/build.css'); - var expected = read(fixture('indent/expected.css'), 'utf8').trim(); + it('should override imports with "file" as input and fires callback with file and contents', function(done) { + var result = sass.renderSync({ + file: fixture('include-files/index.scss'), + importer: function(url, prev, done) { + done({ + file: '/some/other/path.scss', + contents: 'div {color: yellow;}' + }); + } + }); - sass.renderFile({ + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }); + + it('should override imports with "data" as input and returns file and contents', function(done) { + var result = sass.renderSync({ data: src, - outFile: dest, - indentedSyntax: true, - success: function() { - assert.equal(read(dest, 'utf8').trim(), expected.replace(/\r\n/g, '\n')); - fs.unlinkSync(dest); - done(); + importer: function(url, prev) { + return { + file: prev + url, + contents: 'div {color: yellow;}' + }; } }); + + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); }); - it('should save source map to default name', function(done) { - var src = fixture('source-map/index.scss'); - var dest = fixture('source-map/build.css'); - var name = 'build.css.map'; + it('should override imports with "file" as input and returns file and contents', function(done) { + var result = sass.renderSync({ + file: fixture('include-files/index.scss'), + importer: function(url, prev) { + return { + file: prev + url, + contents: 'div {color: yellow;}' + }; + } + }); - sass.renderFile({ - file: src, - outFile: dest, - sourceMap: true, - success: function(file, map) { - assert.equal(path.basename(map), name); - assert(read(dest, 'utf8').indexOf('sourceMappingURL=' + name) !== -1); - fs.unlinkSync(map); - fs.unlinkSync(dest); - done(); + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }); + + it('should override imports with "data" as input and fires callback with file', function(done) { + var result = sass.renderSync({ + data: src, + importer: function(url, /* jshint unused:false */ prev, done) { + done({ + file: path.resolve(path.dirname(fixture('include-files/index.scss')), url + (path.extname(url) ? '' : '.scss')) + }); } }); + + assert.equal(result.css.trim(), ''); + done(); }); - it('should save source map to specified name', function(done) { - var src = fixture('source-map/index.scss'); - var dest = fixture('source-map/build.css'); - var name = 'foo.css.map'; + it('should override imports with "file" as input and fires callback with file', function(done) { + var result = sass.renderSync({ + file: fixture('include-files/index.scss'), + importer: function(url, prev, done) { + done({ + file: path.resolve(path.dirname(prev), url + (path.extname(url) ? '' : '.scss')) + }); + } + }); - sass.renderFile({ - file: src, - outFile: dest, - sourceMap: name, - success: function(file, map) { - assert.equal(path.basename(map), name); - assert(read(dest, 'utf8').indexOf('sourceMappingURL=' + name) !== -1); - fs.unlinkSync(map); - fs.unlinkSync(dest); - done(); + assert.equal(result.css.trim(), ''); + done(); + }); + + it('should override imports with "data" as input and returns file', function(done) { + var result = sass.renderSync({ + data: src, + importer: function(url, /* jshint unused:false */ prev) { + return { + file: path.resolve(path.dirname(fixture('include-files/index.scss')), url + (path.extname(url) ? '' : '.scss')) + }; } }); + + assert.equal(result.css.trim(), ''); + done(); }); - it('should save source paths relative to the source map file', function(done) { - var src = fixture('include-files/index.scss'); - var dest = fixture('include-files/build.css'); - var obj; + it('should override imports with "file" as input and returns file', function(done) { + var result = sass.renderSync({ + file: fixture('include-files/index.scss'), + importer: function(url, prev) { + return { + file: path.resolve(path.dirname(prev), url + (path.extname(url) ? '' : '.scss')) + }; + } + }); - sass.renderFile({ - file: src, - outFile: dest, - sourceMap: true, - success: function(file, map) { - obj = JSON.parse(read(map, 'utf8')); - assert.equal(obj.sources[0], 'index.scss'); - assert.equal(obj.sources[1], 'foo.scss'); - assert.equal(obj.sources[2], 'bar.scss'); - fs.unlinkSync(map); - fs.unlinkSync(dest); - done(); + assert.equal(result.css.trim(), ''); + done(); + }); + + it('should override imports with "data" as input and fires callback with contents', function(done) { + var result = sass.renderSync({ + data: src, + importer: function(url, prev, done) { + done({ + contents: 'div {color: yellow;}' + }); + } + }); + + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }); + + it('should override imports with "file" as input and fires callback with contents', function(done) { + var result = sass.renderSync({ + file: fixture('include-files/index.scss'), + importer: function(url, prev, done) { + done({ + contents: 'div {color: yellow;}' + }); + } + }); + + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }); + + it('should override imports with "data" as input and returns contents', function(done) { + var result = sass.renderSync({ + data: src, + importer: function() { + return { + contents: 'div {color: yellow;}' + }; + } + }); + + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); + }); + + it('should override imports with "file" as input and returns contents', function(done) { + var result = sass.renderSync({ + file: fixture('include-files/index.scss'), + importer: function() { + return { + contents: 'div {color: yellow;}' + }; } }); + + assert.equal(result.css.trim(), 'div {\n color: yellow; }\n\ndiv {\n color: yellow; }'); + done(); }); }); describe('.render({stats: {}})', function() { var start = Date.now(); - var stats = {}; - before(function(done) { + it('should provide a start timestamp', function(done) { sass.render({ file: fixture('include-files/index.scss'), - stats: stats, - success: function() { + success: function(result) { + assert(typeof result.stats.start === 'number'); + assert(result.stats.start >= start); done(); }, error: function(err) { @@ -345,27 +555,48 @@ describe('api', function() { }); }); - it('should provide a start timestamp', function(done) { - assert(typeof stats.start === 'number'); - assert(stats.start >= start); - done(); - }); - it('should provide an end timestamp', function(done) { - assert(typeof stats.end === 'number'); - assert(stats.end >= stats.start); - done(); + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert(typeof result.stats.end === 'number'); + assert(result.stats.end >= result.stats.start); + done(); + }, + error: function(err) { + assert(!err); + done(); + } + }); }); it('should provide a duration', function(done) { - assert(typeof stats.duration === 'number'); - assert.equal(stats.end - stats.start, stats.duration); - done(); + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert(typeof result.stats.duration === 'number'); + assert.equal(result.stats.end - result.stats.start, result.stats.duration); + done(); + }, + error: function(err) { + assert(!err); + done(); + } + }); }); it('should contain the given entry file', function(done) { - assert.equal(stats.entry, fixture('include-files/index.scss')); - done(); + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert.equal(result.stats.entry, fixture('include-files/index.scss')); + done(); + }, + error: function(err) { + assert(!err); + done(); + } + }); }); it('should contain an array of all included files', function(done) { @@ -375,8 +606,17 @@ describe('api', function() { fixture('include-files/index.scss').replace(/\\/g, '/') ]; - assert.deepEqual(stats.includedFiles, expected); - done(); + sass.render({ + file: fixture('include-files/index.scss'), + success: function(result) { + assert.deepEqual(result.stats.includedFiles, expected); + done(); + }, + error: function(err) { + assert(!err); + done(); + } + }); }); it('should contain array with the entry if there are no import statements', function(done) { @@ -384,9 +624,8 @@ describe('api', function() { sass.render({ file: fixture('simple/index.scss'), - stats: stats, - success: function() { - assert.deepEqual(stats.includedFiles, [expected]); + success: function(result) { + assert.deepEqual(result.stats.includedFiles, [expected]); done(); } }); @@ -395,9 +634,8 @@ describe('api', function() { it('should state `data` as entry file', function(done) { sass.render({ data: read(fixture('simple/index.scss'), 'utf8'), - stats: stats, - success: function() { - assert.equal(stats.entry, 'data'); + success: function(result) { + assert.equal(result.stats.entry, 'data'); done(); } }); @@ -406,22 +644,8 @@ describe('api', function() { it('should contain an empty array as includedFiles', function(done) { sass.render({ data: read(fixture('simple/index.scss'), 'utf8'), - stats: stats, - success: function() { - assert.deepEqual(stats.includedFiles, []); - done(); - } - }); - }); - - it('should report correct source map in stats', function(done) { - sass.render({ - file: fixture('simple/index.scss'), - outFile: fixture('simple/build.css'), - stats: stats, - sourceMap: true, - success: function() { - assert.equal(stats.sourceMap.sources[0], 'index.scss'); + success: function(result) { + assert.deepEqual(result.stats.includedFiles, []); done(); } }); @@ -430,35 +654,30 @@ describe('api', function() { describe('.renderSync({stats: {}})', function() { var start = Date.now(); - var stats = {}; - - before(function() { - sass.renderSync({ - file: fixture('include-files/index.scss'), - stats: stats - }); + var result = sass.renderSync({ + file: fixture('include-files/index.scss') }); it('should provide a start timestamp', function(done) { - assert(typeof stats.start === 'number'); - assert(stats.start >= start); + assert(typeof result.stats.start === 'number'); + assert(result.stats.start >= start); done(); }); it('should provide an end timestamp', function(done) { - assert(typeof stats.end === 'number'); - assert(stats.end >= stats.start); + assert(typeof result.stats.end === 'number'); + assert(result.stats.end >= result.stats.start); done(); }); it('should provide a duration', function(done) { - assert(typeof stats.duration === 'number'); - assert.equal(stats.end - stats.start, stats.duration); + assert(typeof result.stats.duration === 'number'); + assert.equal(result.stats.end - result.stats.start, result.stats.duration); done(); }); it('should contain the given entry file', function(done) { - assert.equal(stats.entry, resolveFixture('include-files/index.scss')); + assert.equal(result.stats.entry, resolveFixture('include-files/index.scss')); done(); }); @@ -469,60 +688,49 @@ describe('api', function() { fixture('include-files/index.scss').replace(/\\/g, '/') ]; - assert.equal(stats.includedFiles[0], expected[0]); - assert.equal(stats.includedFiles[1], expected[1]); - assert.equal(stats.includedFiles[2], expected[2]); + assert.equal(result.stats.includedFiles[0], expected[0]); + assert.equal(result.stats.includedFiles[1], expected[1]); + assert.equal(result.stats.includedFiles[2], expected[2]); done(); }); it('should contain array with the entry if there are no import statements', function(done) { var expected = fixture('simple/index.scss').replace(/\\/g, '/'); - sass.renderSync({ - file: fixture('simple/index.scss'), - stats: stats + var result = sass.renderSync({ + file: fixture('simple/index.scss') }); - assert.deepEqual(stats.includedFiles, [expected]); + assert.deepEqual(result.stats.includedFiles, [expected]); done(); }); it('should state `data` as entry file', function(done) { - sass.renderSync({ - data: read(fixture('simple/index.scss'), 'utf8'), - stats: stats + var result = sass.renderSync({ + data: read(fixture('simple/index.scss'), 'utf8') }); - assert.equal(stats.entry, 'data'); + assert.equal(result.stats.entry, 'data'); done(); }); it('should contain an empty array as includedFiles', function(done) { - sass.renderSync({ - data: read(fixture('simple/index.scss'), 'utf8'), - stats: stats + var result = sass.renderSync({ + data: read(fixture('simple/index.scss'), 'utf8') }); - assert.deepEqual(stats.includedFiles, []); - done(); - }); - - it('should report correct source map in stats', function(done) { - sass.renderSync({ - file: fixture('simple/index.scss'), - outFile: fixture('simple/build.css'), - stats: stats, - sourceMap: true - }); - - assert.equal(stats.sourceMap.sources[0], 'index.scss'); + assert.deepEqual(result.stats.includedFiles, []); done(); }); }); - describe('.middleware()', function() { - it('should throw error on require', function(done) { - assert.throws(sass.middleware()); + describe('.info()', function() { + it('should return a correct version info', function(done) { + assert.equal(sass.info(), [ + 'node-sass version: ' + require('../package.json').version, + 'libsass version: ' + require('../package.json').libsass + ].join('\n')); + done(); }); }); diff --git a/test/cli.js b/test/cli.js index 8e5eceefd..81408beb2 100644 --- a/test/cli.js +++ b/test/cli.js @@ -223,4 +223,106 @@ describe('cli', function() { }); }); }); + + describe('importer', function() { + var dest = fixture('include-files/index.css'); + var src = fixture('include-files/index.scss'); + var expected = read(fixture('include-files/expected-importer.css'), 'utf8').trim().replace(/\r\n/g, '\n'); + + it('should override imports and fire callback with file and contents', function(done) { + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--importer', fixture('extras/my_custom_importer_file_and_data_cb.js') + ]); + + bin.on('close', function () { + assert.equal(read(dest, 'utf8').trim(), expected); + fs.unlinkSync(dest); + done(); + }); + }); + + it('should override imports and fire callback with file', function(done) { + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--importer', fixture('extras/my_custom_importer_file_cb.js') + ]); + + bin.on('close', function () { + if (fs.existsSync(dest)) { + assert.equal(read(dest, 'utf8').trim(), ''); + fs.unlinkSync(dest); + } + + done(); + }); + }); + + it('should override imports and fire callback with data', function(done) { + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--importer', fixture('extras/my_custom_importer_data_cb.js') + ]); + + bin.on('close', function () { + assert.equal(read(dest, 'utf8').trim(), expected); + fs.unlinkSync(dest); + done(); + }); + }); + + it('should override imports and return file and contents', function(done) { + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--importer', fixture('extras/my_custom_importer_file_and_data.js') + ]); + + bin.on('close', function () { + assert.equal(read(dest, 'utf8').trim(), expected); + fs.unlinkSync(dest); + done(); + }); + }); + + it('should override imports and return file', function(done) { + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--importer', fixture('extras/my_custom_importer_file.js') + ]); + + bin.on('close', function () { + if (fs.existsSync(dest)) { + assert.equal(read(dest, 'utf8').trim(), ''); + fs.unlinkSync(dest); + } + + done(); + }); + }); + + it('should override imports and return data', function(done) { + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--importer', fixture('extras/my_custom_importer_data.js') + ]); + + bin.on('close', function () { + assert.equal(read(dest, 'utf8').trim(), expected); + fs.unlinkSync(dest); + done(); + }); + }); + + it('should return error on for invalid importer file path', function(done) { + var bin = spawn(cli, [ + src, '--output', path.dirname(dest), + '--importer', fixture('non/existing/path') + ]); + + bin.on('close', function (code) { + assert(code !== 0); + done(); + }); + }); + }); }); diff --git a/test/fixtures/extras/my_custom_importer_data.js b/test/fixtures/extras/my_custom_importer_data.js new file mode 100644 index 000000000..ed16e226d --- /dev/null +++ b/test/fixtures/extras/my_custom_importer_data.js @@ -0,0 +1,5 @@ +module.exports = function() { + return { + contents: 'div {color: yellow;}' + }; +}; diff --git a/test/fixtures/extras/my_custom_importer_data_cb.js b/test/fixtures/extras/my_custom_importer_data_cb.js new file mode 100644 index 000000000..ce487d1e6 --- /dev/null +++ b/test/fixtures/extras/my_custom_importer_data_cb.js @@ -0,0 +1,5 @@ +module.exports = function(file, prev, done) { + done({ + contents: 'div {color: yellow;}' + }); +}; diff --git a/test/fixtures/extras/my_custom_importer_file.js b/test/fixtures/extras/my_custom_importer_file.js new file mode 100644 index 000000000..b5d831d5a --- /dev/null +++ b/test/fixtures/extras/my_custom_importer_file.js @@ -0,0 +1,7 @@ +var path = require('path'); + +module.exports = function(file) {console.log('>>>>>>>>>>');console.log(path.resolve(path.join(process.cwd(), 'test/fixtures/include-files/', file + (path.extname(file) ? '' : '.scss')))); + return { + file: path.resolve(path.join(process.cwd(), 'test/fixtures/include-files/', file + (path.extname(file) ? '' : '.scss'))) + }; +}; diff --git a/test/fixtures/extras/my_custom_importer_file_and_data.js b/test/fixtures/extras/my_custom_importer_file_and_data.js new file mode 100644 index 000000000..d0c10763f --- /dev/null +++ b/test/fixtures/extras/my_custom_importer_file_and_data.js @@ -0,0 +1,6 @@ +module.exports = function() { + return { + file: '/some/random/path/file.scss', + contents: 'div {color: yellow;}' + }; +}; diff --git a/test/fixtures/extras/my_custom_importer_file_and_data_cb.js b/test/fixtures/extras/my_custom_importer_file_and_data_cb.js new file mode 100644 index 000000000..e72ed660a --- /dev/null +++ b/test/fixtures/extras/my_custom_importer_file_and_data_cb.js @@ -0,0 +1,6 @@ +module.exports = function(file, prev, done) { + done({ + file: '/some/random/path/file.scss', + contents: 'div {color: yellow;}' + }); +}; diff --git a/test/fixtures/extras/my_custom_importer_file_cb.js b/test/fixtures/extras/my_custom_importer_file_cb.js new file mode 100644 index 000000000..71c3ac125 --- /dev/null +++ b/test/fixtures/extras/my_custom_importer_file_cb.js @@ -0,0 +1,7 @@ +var path = require('path'); + +module.exports = function(file, /* jshint unused:false */ prev, done) { + done({ + file: path.resolve(path.join(process.cwd(), 'test/fixtures/include-files/', file + (path.extname(file) ? '' : '.scss'))) + }); +}; diff --git a/test/fixtures/include-files/expected-importer.css b/test/fixtures/include-files/expected-importer.css new file mode 100644 index 000000000..1925a6021 --- /dev/null +++ b/test/fixtures/include-files/expected-importer.css @@ -0,0 +1,5 @@ +div { + color: yellow; } + +div { + color: yellow; } diff --git a/test/fixtures/spec b/test/fixtures/spec index 074ae3b24..00c6154db 160000 --- a/test/fixtures/spec +++ b/test/fixtures/spec @@ -1 +1 @@ -Subproject commit 074ae3b24bfc3ff19a98efdec02415ed6fd5759a +Subproject commit 00c6154dba85a38bb03b89d7279f439feb055821 diff --git a/test/spec.js b/test/spec.js index e6c971178..8d805a472 100644 --- a/test/spec.js +++ b/test/spec.js @@ -40,8 +40,8 @@ describe('spec', function () { sass.render({ file: t.src, includePaths: t.paths, - success: function(css) { - assert.equal(util.normalize(css), expected); + success: function(result) { + assert.equal(util.normalize(result.css), expected); done(); }, error: function(err) {