diff --git a/README.md b/README.md index cdf6c11..8ab94b5 100644 --- a/README.md +++ b/README.md @@ -14,22 +14,27 @@ install via npm: To import a file called `_name.scss`, there are four ways to do it. - @import 'path-to-file/name'; - @import 'path-to-file/_name'; - @import 'path-to-file/name.scss'; - @import 'path-to-file/_name.scss'; +```javascript +@import 'path-to-file/name'; +@import 'path-to-file/_name'; +@import 'path-to-file/name.scss'; +@import 'path-to-file/_name.scss'; +``` All of above will have the same result. +```javascript +'use strict'; - var gulp = require('gulp'); - var gss = require('gulp-shopify-sass'); - - gulp.task('default', function() { - return gulp.src('./*.scss') - .pipe(gss()); - }); +var gulp = require('gulp'); +var gss = require('gulp-shopify-sass'); +gulp.task('default', function() { + return gulp.src('./*.scss') + .pipe(gss()) + .pipe(gulp.dest('./path/to/dist')); +}); +``` # License -MIT license \ No newline at end of file +MIT license diff --git a/index.js b/index.js index 3dec39a..cceadba 100644 --- a/index.js +++ b/index.js @@ -1,130 +1,159 @@ 'use strict'; -var through = require('through2'); -var path = require('path'); -var gutil = require('gulp-util'); -var PluginError = gutil.PluginError; -var vfile = require('vinyl-file'); -var vinyl = require('vinyl'); -var fs = require('fs'); +var path = require('path'); +var gutil = require('gulp-util'); +var through = require('through2'); +var clonedeep = require('lodash.clonedeep'); const PLUGIN_NAME = 'gulp-shopify-sass'; -// @param: dir full path and name -// @return: boolean -function checkFileExist (dir) { - try { - fs.accessSync(dir , fs.F_OK); - return true; - } catch (e) { - return false; - } -} - -// @param: dir full path and name -// @return: string | boolean -function analyseDir (dir) { - // possible extension array - const dirReg = new RegExp(/(.+\/)(.+)$/, 'g'); - const filenameReg = new RegExp(/^(\_)?(?:(.*(?=.scss))(.*)|(.*))$/, 'i'); - - // split whole path into path the filename - let pathAndName = dirReg.exec(dir); - - const filepath = pathAndName[1] || ''; - let filename = pathAndName[2] || ''; - - // [0] original filename - // [1] '_' if exist in the filename, otherwise undefined - // [2] filename if it has extension .scss or .scss.liquid, otherwise undefined - // [3] file extension if filename has extionsion .scss or .scss.liquid, otherwise undefined - // [4] filename if it doesn't have extension, otherwise undefined - let filenameFrags = filenameReg.exec(filename); - - // move filename[4] to filename[2] if filename[2] is undefined - filenameFrags[2] = filenameFrags[2] || filenameFrags[4]; - - // remove original name, all index will reduce 1 - filenameFrags.shift(); - - // remove filename[4] since it's been moved to [2] - filenameFrags.pop() - - // [0] was [1], [2] was [3] - let prefix = filenameFrags[0] ? [filenameFrags[0]] : ['', '_']; - let suffix = filenameFrags[2] ? [filenameFrags[2]] : ['.scss', '.scss.liquid']; - let allCombinations = []; - - // check all possible combimations - for (let i in prefix) { - for (let j in suffix) { - filenameFrags[0] = prefix[i]; - filenameFrags[2] = suffix[j]; - filename = filenameFrags.join(''); - - pathAndName = path.join(filepath, filename); - - if (checkFileExist(pathAndName)) { - return pathAndName; - } - } - } - - gutil.log('File to import: "' + dir + '" not found.'); - - return false; -} - - -function importReplacer (file) { - - var rex = /@import\s*(?:(?:'([^']+)')|(?:"([^"]+)"))\s*;/gi; - var fileContents = file.contents.toString(); - var fileDirname = path.dirname(file.path); - var imports = {}; - var match; +/* + * Most of the code in index.js are copied from gulp-sass + */ - while(match = rex.exec(fileContents)) { - - // [1] single quotes - // [2] double quotes - var importFile = path.join(fileDirname, (match[1] || match[2])); +////////////////////////////// +// Main Gulp Shopify Sass function +////////////////////////////// +var gulpShopifySass = function gulpShopifySass (options, sync) { + return through.obj(function (file, enc, cb) { - const fileExistCheck = analyseDir(importFile); + var opts, contents; - // if file exists, replace it - if(fileExistCheck) { - imports[match[0]] = fileExistCheck; + if (file.isNull()) { + return cb(null, file); } - } - - for(let imp in imports) { - // replace @import with import file contents - fileContents = fileContents.replace(new RegExp(imp, 'g'), importReplacer(vfile.readSync(imports[imp])).contents.toString()); - } - - file.contents = new Buffer(fileContents); - - return file; -} - -module.exports = function () { - return through.obj(function (file, enc, cb) { - // do not support stream if(file.isStream()) { - this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!')); - return cb(); + return cb(new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported!')); } + ////////////////////////////// + // Handles returning the file to the stream + ////////////////////////////// + var filePush = function filePush(contents) { + // console.log(file); + // console.log(file.contents); + // console.log(contents); + // file = new gutil.File({ + // 'cwd': __dirname, + // 'base': file.base, + // 'path': gutil.replaceExtension(file.path, '.cat.scss.liquid'), + // 'contents': contents + // }); + + file.contents = new Buffer(contents); + file.path = gutil.replaceExtension(file.path, '.cat.scss.liquid'); + + cb(null, file); + }; + + ////////////////////////////// + // Handles error message + ////////////////////////////// + var errorM = function errorM(error) { + var relativePath = '', + filePath = error.file === 'stdin' ? file.path : error.file, + message = ''; + + filePath = filePath ? filePath : file.path; + relativePath = path.relative(process.cwd(), filePath); + + message += gutil.colors.underline(relativePath) + '\n'; + message += error.formatted; + + error.messageFormatted = message; + error.messageOriginal = error.message; + // error.message = gutil.colors.stripColor(message); + + error.relativePath = relativePath; + + return cb(new gutil.PluginError( + PLUGIN_NAME, error + )); + }; + // processing buffer if(file.isBuffer()) { - importReplacer(file); + ////////////////////////////// + // gulpShopifySass main process BEGIN + ////////////////////////////// + + opts = clonedeep(options || {}); + opts.data = file.contents.toString(); + + // we set the file path here so that libsass can correctly resolve import paths + opts.file = file.path; + + // TODO: add includePaths feature in options and relavent processer + + // Ensure file's parent directory in the include path + // if (opts.includePaths) { + // if (typeof opts.includePaths === 'string') { + // opts.includePaths = [opts.includePaths]; + // } + // } else { + // opts.includePaths = []; + // } + + // opts.includePaths.unshift(path.dirname(file.path)); + + // TDDO: enable sync option once async render is done. Only support renderSync for now + // if (sync === true) { + ////////////////////////////// + // Sync Sass render + ////////////////////////////// + + try { + contents = gulpShopifySass.compiler.renderSync(opts); + + filePush(contents); + } catch (error) { + return errorM(error); + } + + // } else { + // ////////////////////////////// + // // Async Sass render + // ////////////////////////////// + // var callback = function(error, catFile) { + // if (error) { + // return errorM(error); + // } + // filePush(catFile); + // }; + + // gulpShopifySass.compiler.render(opts, callback); + // } + ////////////////////////////// + // gulpShopifySass main process END + ////////////////////////////// } - - this.push(file); - - cb(); }); } + +////////////////////////////// +// Sync Shopify Sass render +////////////////////////////// + +// TDDO: enable sync option once async render is done. Only support renderSync for now + +// gulpShopifySass.sync = function sync(options) { +// return gulpShopifySass(options, true); +// }; + +////////////////////////////// +// Log errors nicely +////////////////////////////// +gulpShopifySass.logError = function logError(error) { + var message = new gutil.PluginError('sass', error.messageFormatted).toString(); + process.stderr.write(message + '\n'); + this.emit('end'); +}; + +////////////////////////////// +// Store compiler in a prop +////////////////////////////// +gulpShopifySass.compiler = require('./lib/compiler'); + +module.exports = gulpShopifySass; diff --git a/lib/compiler.js b/lib/compiler.js new file mode 100644 index 0000000..ba2fcb3 --- /dev/null +++ b/lib/compiler.js @@ -0,0 +1,255 @@ +/* + * gulp-shopify-sass: lib/compiler.js + */ + +// TODO: not done +/* + * Goal: create scss syntax parser to replace RegExp, in order to add extra features, such as + * 1. Regonize @import in comments and do not replace it + * 2. Support includePaths option to minimize @import path length in each file + */ + +var fs = require('fs'); +var path = require('path'); +var clonedeep = require('lodash.clonedeep'); +var vfile = require('vinyl-file'); +// var vinyl = require('vinyl'); +/** + * Get options + * + * @param {Object} options + * @api private + */ + +function getOptions(opts, cb) { + var options = clonedeep(opts || {}); + + // TODO: preprocess options + + // options.sourceComments = options.sourceComments || true; + // if (options.hasOwnProperty('file')) { + // options.file = getInputFile(options); + // } + // options.outFile = getOutputFile(options); + // options.includePaths = buildIncludePaths(options); + + // context object represents node-sass environment + // options.context = { options: options, callback: cb }; + + return options; +} + +/** + * Get input file + * + * @param {Object} options + * @api private + */ + +function getInputFile(options) { + return options.file ? path.resolve(options.file) : null; +} + +/** + * Get output file + * + * @param {Object} options + * @api private + */ + +function getOutputFile(options) { + var outFile = options.outFile; + + if (!outFile || typeof outFile !== 'string' || (!options.data && !options.file)) { + return null; + } + + return path.resolve(outFile); +} + +/** + * Build an includePaths string + * from the options.includePaths array and the SASS_PATH environment variable + * + * @param {Object} options + * @api private + */ + +function buildIncludePaths(options) { + options.includePaths = options.includePaths || []; + + if (process.env.hasOwnProperty('SASS_PATH')) { + options.includePaths = options.includePaths.concat( + process.env.SASS_PATH.split(path.delimiter) + ); + } + + return options.includePaths.join(path.delimiter); +} + +// @param: {string} dir full path and name +// @return: {boolean} +function checkFileExist (dir) { + try { + fs.accessSync(dir , fs.F_OK); + + return true; + } catch (e) { + return false + } +} + +// @param: dir full path and name +// @return: string | boolean +function analyseDir (dir) { + // possible extension array + const dirReg = new RegExp(/(.+\/)(.+)$/, 'g'); + const filenameReg = new RegExp(/^(\_)?(?:(.*(?=.scss))(.*)|(.*))$/, 'i'); + + // split whole path into path the filename + let pathAndName = dirReg.exec(dir); + + const filepath = pathAndName[1] || ''; + let filename = pathAndName[2] || ''; + + // [0] original filename + // [1] '_' if exist in the filename, otherwise undefined + // [2] filename if it has extension .scss or .scss.liquid, otherwise undefined + // [3] file extension if filename has extionsion .scss or .scss.liquid, otherwise undefined + // [4] filename if it doesn't have extension, otherwise undefined + let filenameFrags = filenameReg.exec(filename); + + // move filename[4] to filename[2] is filename[2] is undefined + filenameFrags[2] = filenameFrags[2] || filenameFrags[4]; + + let prefix = filenameFrags[1] ? [filenameFrags[1]] : ['', '_']; + let suffix = filenameFrags[3] ? [filenameFrags[3]] : ['.scss', '.scss.liquid']; + + // remove original name, all index will reduce 1 + filenameFrags.shift(); + + // remove filename[4] since it's been moved to [2] + filenameFrags.pop() + + // check all possible combimations + for (let i in prefix) { + for (let j in suffix) { + filenameFrags[0] = prefix[i]; + filenameFrags[2] = suffix[j]; + filename = filenameFrags.join(''); + pathAndName = path.join(filepath, filename); + + if (checkFileExist(pathAndName)) { + return pathAndName; + } + } + } + + return new Error('File to import: "' + dir + '" not found.'); +} + + +function importReplacer (options) { + + var rex = /@import\s*(?:(?:'([^']+)')|(?:"([^"]+)"))\s*;\s*$/gmi; + var contents = options.data; + var dirname = path.dirname(options.file); + var imports = {}; + var match; + + while(match = rex.exec(contents)) { + + // [1] single quotes + // [2] double quotes + var importFile = path.join(dirname, (match[1] || match[2])); + + const fileExistCheck = analyseDir(importFile); + + // if file exists, replace it + if(fileExistCheck) { + imports[match[0]] = fileExistCheck; + } + + } + + for(let imp in imports) { + + // replace @import with import file contents + let file = vfile.readSync(imports[imp]); + let result = importReplacer({ + data: file.contents.toString(), + file: file.path + }); + + contents = contents.replace(new RegExp(imp, 'g'), result); + } + + return contents; +} + +/** + * Render + * + * @param {Object} opts + * @param {cb} function + * @api public + */ + + +// TODO: add async render functionality + +// module.exports.render = function(opts, callback) { +// var options = getOptions(opts, callback); + +// // options.error and options.success are for libsass binding +// options.error = function(err) { +// var payload = assign(new Error(), JSON.parse(err)); + +// if (callback) { +// options.context.callback.call(options.context, payload, null); +// } +// }; + +// options.success = function() { +// var result = options.result; +// var stats = endStats(result.stats); +// var payload = { +// css: result.css, +// map: result.map, +// stats: stats +// }; + +// if (callback) { +// options.context.callback.call(options.context, null, payload); +// } +// }; + +// // todo +// importReplacer(options, callback); +// }; + +/** + * Render sync + * + * @param {Object} options + * @api public + */ + +module.exports.renderSync = function(options) { + // var options = getOptions(opts); + // var importer = options.importer; + + // todo + // var status = importReplacer(options); + + return importReplacer(options); + + // var result = options.result; + + // if (status) { + // result.stats = endStats(result.stats); + // return result; + // } + + // throw assign(new Error(), JSON.parse(result.error)); +}; \ No newline at end of file diff --git a/lib/parser.js b/lib/parser.js new file mode 100644 index 0000000..e69de29 diff --git a/lib/parser.pegjs b/lib/parser.pegjs new file mode 100644 index 0000000..a3d111f --- /dev/null +++ b/lib/parser.pegjs @@ -0,0 +1,36 @@ +// TODO: not done +/* + * Goal: create scss syntax parser to replace RegExp, in order to add extra features, such as + * 1. Regonize @import in comments and do not replace it + * 2. Support includePaths option to minimize @import path length in each file + */ + +{ + var unroll = options.util.makeUnroll(location, options) + var ast = options.util.makeAST (location, options) +} + +start + = _ seq:id_seq _ { + return ast("Sample").add(seq) + } + +id_seq + = id:id ids:(_ "," _ id)* { + return ast("IdentifierSequence").add(unroll(id, ids, 3)) + } + +id + = id:$([a-zA-Z_][a-zA-Z0-9_]*) { + return ast("Identifier").set("name", id) + } + +_ "blank" + = (co / ws)* + +co "comment" + = "//" (![\r\n] .)* + / "/*" (!"*/" .)* "*/" + +ws "whitespaces" + = [ \t\r\n]+ \ No newline at end of file diff --git a/package.json b/package.json index 6824092..0222fe9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gulp-shopify-sass", - "version": "0.3.1", + "version": "0.3.2", "description": "Concatenate Sass files defined by the @import order", "main": "./index.js", "scripts": { @@ -25,7 +25,10 @@ "devDependencies": { "event-stream": "^3.3.2", "gulp": "^3.9.0", + "lodash.clonedeep": "^4.5.0", "mocha": "^2.3.4", + "pegjs": "^0.10.0", + "pegjs-util": "^1.3.5", "should": "^8.1.1", "stream-array": "^1.1.1", "stream-assert": "^2.0.3" diff --git a/test/fixtures/_dash.scss.liquid b/test/fixtures/_dash.scss.liquid deleted file mode 100644 index 6a6d300..0000000 --- a/test/fixtures/_dash.scss.liquid +++ /dev/null @@ -1 +0,0 @@ -.dash {} \ No newline at end of file diff --git a/test/fixtures/_underscore.scss.liquid b/test/fixtures/_underscore.scss.liquid deleted file mode 100644 index 39026fe..0000000 --- a/test/fixtures/_underscore.scss.liquid +++ /dev/null @@ -1 +0,0 @@ -.class-name-no-show {} \ No newline at end of file diff --git a/test/fixtures/a.scss b/test/fixtures/a.scss deleted file mode 100644 index 6f62ae2..0000000 --- a/test/fixtures/a.scss +++ /dev/null @@ -1 +0,0 @@ -.class-name {} \ No newline at end of file diff --git a/test/fixtures/b.scss b/test/fixtures/b.scss deleted file mode 100644 index e48e08c..0000000 --- a/test/fixtures/b.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'a.scss'; \ No newline at end of file diff --git a/test/fixtures/c.scss b/test/fixtures/c.scss deleted file mode 100644 index 5dba76a..0000000 --- a/test/fixtures/c.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'b.scss'; \ No newline at end of file diff --git a/test/fixtures/d.scss b/test/fixtures/d.scss deleted file mode 100644 index ee9df4a..0000000 --- a/test/fixtures/d.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'a.scss'; -@import 'a.scss'; \ No newline at end of file diff --git a/test/fixtures/e.scss b/test/fixtures/e.scss deleted file mode 100644 index 28675be..0000000 --- a/test/fixtures/e.scss +++ /dev/null @@ -1,4 +0,0 @@ -@import 'underscore'; -@import '_underscore'; -@import 'underscore.scss'; -@import '_underscore.scss'; \ No newline at end of file diff --git a/test/fixtures/expected/extentionOverride.cat.scss.liquid b/test/fixtures/expected/extentionOverride.cat.scss.liquid new file mode 100644 index 0000000..de154db --- /dev/null +++ b/test/fixtures/expected/extentionOverride.cat.scss.liquid @@ -0,0 +1,2 @@ +.class-name {} +.class-name-liquid {} \ No newline at end of file diff --git a/test/fixtures/expected/import.liquid.cat.scss.liquid b/test/fixtures/expected/import.liquid.cat.scss.liquid new file mode 100644 index 0000000..edf53e8 --- /dev/null +++ b/test/fixtures/expected/import.liquid.cat.scss.liquid @@ -0,0 +1,4 @@ +.class-name-liquid {} +.class-name-liquid {} +.class-name-liquid {} +.class-name-liquid {} \ No newline at end of file diff --git a/test/fixtures/expected/multiple.cat.scss.liquid b/test/fixtures/expected/multiple.cat.scss.liquid new file mode 100644 index 0000000..0a51a23 --- /dev/null +++ b/test/fixtures/expected/multiple.cat.scss.liquid @@ -0,0 +1,2 @@ +.class-name {} +.class-name {} \ No newline at end of file diff --git a/test/fixtures/expected/variations.cat.scss.liquid b/test/fixtures/expected/variations.cat.scss.liquid new file mode 100644 index 0000000..e8d9d96 --- /dev/null +++ b/test/fixtures/expected/variations.cat.scss.liquid @@ -0,0 +1,4 @@ +.class-name {} +.class-name {} +.class-name {} +.class-name {} \ No newline at end of file diff --git a/test/fixtures/f.scss b/test/fixtures/f.scss deleted file mode 100644 index e8a66d6..0000000 --- a/test/fixtures/f.scss +++ /dev/null @@ -1,4 +0,0 @@ -@import 'dash'; -@import '_dash'; -@import 'dash.scss.liquid'; -@import '_dash.scss.liquid'; \ No newline at end of file diff --git a/test/fixtures/g.scss b/test/fixtures/g.scss deleted file mode 100644 index c18eccf..0000000 --- a/test/fixtures/g.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'underscore'; -@import '_underscore'; \ No newline at end of file diff --git a/test/fixtures/_underscore.scss b/test/fixtures/scss/_single.scss similarity index 100% rename from test/fixtures/_underscore.scss rename to test/fixtures/scss/_single.scss diff --git a/test/fixtures/scss/_single.scss.liquid b/test/fixtures/scss/_single.scss.liquid new file mode 100644 index 0000000..67a4ac0 --- /dev/null +++ b/test/fixtures/scss/_single.scss.liquid @@ -0,0 +1 @@ +.class-name-liquid {} \ No newline at end of file diff --git a/test/fixtures/scss/_single_liquid.scss.liquid b/test/fixtures/scss/_single_liquid.scss.liquid new file mode 100644 index 0000000..67a4ac0 --- /dev/null +++ b/test/fixtures/scss/_single_liquid.scss.liquid @@ -0,0 +1 @@ +.class-name-liquid {} \ No newline at end of file diff --git a/test/fixtures/scss/empty.scss b/test/fixtures/scss/empty.scss new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/scss/extensionOverride.scss b/test/fixtures/scss/extensionOverride.scss new file mode 100644 index 0000000..5d26fdb --- /dev/null +++ b/test/fixtures/scss/extensionOverride.scss @@ -0,0 +1,2 @@ +@import 'single'; +@import '_single.scss.liquid'; \ No newline at end of file diff --git a/test/fixtures/scss/import.liquid.scss b/test/fixtures/scss/import.liquid.scss new file mode 100644 index 0000000..7060c8c --- /dev/null +++ b/test/fixtures/scss/import.liquid.scss @@ -0,0 +1,4 @@ +@import 'single_liquid'; +@import '_single_liquid'; +@import 'single_liquid.scss.liquid'; +@import '_single_liquid.scss.liquid'; \ No newline at end of file diff --git a/test/fixtures/scss/import.scss b/test/fixtures/scss/import.scss new file mode 100644 index 0000000..d1d05cc --- /dev/null +++ b/test/fixtures/scss/import.scss @@ -0,0 +1 @@ +@import 'single'; \ No newline at end of file diff --git a/test/fixtures/scss/multiple.scss b/test/fixtures/scss/multiple.scss new file mode 100644 index 0000000..30b5c6c --- /dev/null +++ b/test/fixtures/scss/multiple.scss @@ -0,0 +1,2 @@ +@import 'single'; +@import 'single'; \ No newline at end of file diff --git a/test/fixtures/scss/recursive.scss b/test/fixtures/scss/recursive.scss new file mode 100644 index 0000000..5f31530 --- /dev/null +++ b/test/fixtures/scss/recursive.scss @@ -0,0 +1 @@ +@import 'import'; \ No newline at end of file diff --git a/test/fixtures/scss/variations.scss b/test/fixtures/scss/variations.scss new file mode 100644 index 0000000..b67c55e --- /dev/null +++ b/test/fixtures/scss/variations.scss @@ -0,0 +1,4 @@ +@import 'single'; +@import '_single'; +@import 'single.scss'; +@import '_single.scss'; \ No newline at end of file diff --git a/test/test-stream.js b/test/test-stream.js deleted file mode 100644 index 8a8ef95..0000000 --- a/test/test-stream.js +++ /dev/null @@ -1,18 +0,0 @@ -var array = require('stream-array'); -var path = require('path'); -var File = require('vinyl'); - -module.exports = function () { - var args = Array.prototype.slice.call(arguments); - - var i = 0; - - return array(args.map(function (contents) { - return new File({ - cwd: path.join(__dirname, '/'), - base: path.join(__dirname, '/fixtures'), - path: path.join(__dirname, '/fixtures/file' + (i++).toString() + '.scss'), - contents: new Buffer(contents) - }); - })); -} diff --git a/test/test.js b/test/test.js index 20f3521..6c2a855 100644 --- a/test/test.js +++ b/test/test.js @@ -2,91 +2,206 @@ var assert = require('stream-assert'); var should = require('should'); var File = require('vinyl'); var gulp = require('gulp'); +var path = require('path'); +var gutil = require('gulp-util'); +var fs = require('fs'); var gulpShopifySass = require('../index'); -var test = require('./test-stream'); -describe('gulp-shopify-sass', function () { - describe('in buffer mode', function () { +var createVinyl = function createVinyl(filename, contents) { + var base = path.join(__dirname, 'fixtures', 'scss'); + var filePath = path.join(base, filename); + return new gutil.File({ + 'cwd': __dirname, + 'base': base, + 'path': filePath, + 'contents': contents || fs.readFileSync(filePath) + }); +}; + +describe('gulp-shopify-sass', function() { + it('skip files doesn\'t exist', function(done) { + var stream = gulpShopifySass(); + var emptyFile = { + 'isNull': function() { + return true; + } + }; - it('skip files doesn\'t exist', function (done) { - test('@import "foo.scss";') - .pipe(gulpShopifySass()) - .pipe(assert.length(1)) - .pipe(assert.first(function(f){f.contents.toString().should.equal('@import "foo.scss";')})) - .pipe(assert.end(done)); + stream.on('data', function (data) { + data.should.equal(emptyFile); + done(); + }); + + stream.write(emptyFile); }); - it('work on single sass file', function (done) { - test('.class-name{}') - .pipe(gulpShopifySass()) - .pipe(assert.length(1)) - .pipe(assert.first(function(f){f.contents.toString().should.equal('.class-name{}')})) - .pipe(assert.end(done)); + it('should emit error when file isStream()', function(done) { + var stream = gulpShopifySass(); + var streamFile = { + 'isNull': function() { + return false; + }, + 'isStream': function() { + return true; + } + }; + + stream.on('error', function (err) { + err.message.should.equal('Streaming not supported!'); + done(); + }); + + stream.write(streamFile); }); - // it('replace import on single file', function (done) { - // test('@import "file1.scss";', '.class-name{}') - // .pipe(gulpShopifySass()) - // .pipe(assert.length(2)) - // .pipe(assert.first(function(f){f.contents.toString().should.equal('.class-name{}')})) - // .pipe(assert.end(done)); - // }); - - // it('replace import recursively', function (done) { - // test('@import "file1.scss";', '@import "file2.scss";', '.class-name{}') - // .pipe(gulpShopifySass()) - // .pipe(assert.length(3)) - // .pipe(assert.first(function(f){f.contents.toString().should.equal('.class-name{}')})) - // .pipe(assert.end(done)); - // }); - - it('replace import', function (done) { - gulp.src('./test/fixtures/b.scss') - .pipe(gulpShopifySass()) - .pipe(assert.length(1)) - .pipe(assert.first(function(f){f.contents.toString().should.equal('.class-name {}')})) - .pipe(assert.end(done)); + it('should compile an empty sass file', function(done) { + var sassFile = createVinyl('empty.scss'); + var stream = gulpShopifySass(); + + stream.on('data', function(catScssFile) { + should.exist(catScssFile); + should.exist(catScssFile.path); + should.exist(catScssFile.relative); + should.exist(catScssFile.contents); + should.equal(path.basename(catScssFile.path), 'empty.cat.scss.liquid'); + String(catScssFile.contents).should.equal(''); + done(); + }); + + stream.write(sassFile); }); - it('replace import recursively', function (done) { - gulp.src('./test/fixtures/c.scss') - .pipe(gulpShopifySass()) - .pipe(assert.length(1)) - .pipe(assert.first(function(f){f.contents.toString().should.equal('.class-name {}')})) - .pipe(assert.end(done)); + it('work on single sass file', function(done) { + var sassFile = createVinyl('_single.scss'); + var stream = gulpShopifySass(); + + stream.on('data', function(catScssFile) { + should.exist(catScssFile); + should.exist(catScssFile.path); + should.exist(catScssFile.relative); + should.exist(catScssFile.contents); + should.equal(path.basename(catScssFile.path), '_single.cat.scss.liquid'); + String(catScssFile.contents).should.equal( + fs.readFileSync(path.join(__dirname, 'fixtures', 'scss', '_single.scss'), 'utf8') + ); + done(); + }); + + stream.write(sassFile); }); - it('replace multiple import', function (done) { - gulp.src('./test/fixtures/d.scss') - .pipe(gulpShopifySass()) - .pipe(assert.length(1)) - .pipe(assert.first(function(f){f.contents.toString().should.equal('.class-name {}\n.class-name {}')})) - .pipe(assert.end(done)); + it('should replace import', function(done) { + var sassFile = createVinyl('import.scss'); + var stream = gulpShopifySass(); + + stream.on('data', function(catScssFile) { + should.exist(catScssFile); + should.exist(catScssFile.path); + should.exist(catScssFile.relative); + should.exist(catScssFile.contents); + should.equal(path.basename(catScssFile.path), 'import.cat.scss.liquid'); + String(catScssFile.contents).should.equal( + fs.readFileSync(path.join(__dirname, 'fixtures', 'scss', '_single.scss'), 'utf8') + ); + done(); + }); + + stream.write(sassFile); }); - it('replace multiple types of import', function (done) { - gulp.src('./test/fixtures/e.scss') - .pipe(gulpShopifySass()) - .pipe(assert.length(1)) - .pipe(assert.first(function(f){f.contents.toString().should.equal('.class-name {}\n.class-name {}\n.class-name {}\n.class-name {}')})) - .pipe(assert.end(done)); + it('replace import recursively', function(done) { + var sassFile = createVinyl('recursive.scss'); + var stream = gulpShopifySass(); + + stream.on('data', function(catScssFile) { + should.exist(catScssFile); + should.exist(catScssFile.path); + should.exist(catScssFile.relative); + should.exist(catScssFile.contents); + should.equal(path.basename(catScssFile.path), 'recursive.cat.scss.liquid'); + String(catScssFile.contents).should.equal( + fs.readFileSync(path.join(__dirname, 'fixtures', 'scss', '_single.scss'), 'utf8') + ); + done(); + }); + + stream.write(sassFile); }); - it('replace import .scss.liquid', function (done) { - gulp.src('./test/fixtures/f.scss') - .pipe(gulpShopifySass()) - .pipe(assert.length(1)) - .pipe(assert.first(function(f){f.contents.toString().should.equal('.dash {}\n.dash {}\n.dash {}\n.dash {}')})) - .pipe(assert.end(done)); + it('replace multiple import', function(done) { + var sassFile = createVinyl('multiple.scss'); + var stream = gulpShopifySass(); + + stream.on('data', function(catScssFile) { + should.exist(catScssFile); + should.exist(catScssFile.path); + should.exist(catScssFile.relative); + should.exist(catScssFile.contents); + should.equal(path.basename(catScssFile.path), 'multiple.cat.scss.liquid'); + String(catScssFile.contents).should.equal( + fs.readFileSync(path.join(__dirname, 'fixtures', 'expected', 'multiple.cat.scss.liquid'), 'utf8') + ); + done(); + }); + + stream.write(sassFile); + }); + + it('replace import with different name variations', function(done) { + var sassFile = createVinyl('variations.scss'); + var stream = gulpShopifySass(); + + stream.on('data', function(catScssFile) { + should.exist(catScssFile); + should.exist(catScssFile.path); + should.exist(catScssFile.relative); + should.exist(catScssFile.contents); + should.equal(path.basename(catScssFile.path), 'variations.cat.scss.liquid'); + String(catScssFile.contents).should.equal( + fs.readFileSync(path.join(__dirname, 'fixtures', 'expected', 'variations.cat.scss.liquid'), 'utf8') + ); + done(); + }); + + stream.write(sassFile); }); - it('do not import .scss.liquid if .scss exist', function (done) { - gulp.src('./test/fixtures/g.scss') - .pipe(gulpShopifySass()) - .pipe(assert.length(1)) - .pipe(assert.first(function(f){f.contents.toString().should.equal('.class-name {}\n.class-name {}')})) - .pipe(assert.end(done)); + it('replace import .scss.liquid', function(done) { + var sassFile = createVinyl('import.liquid.scss'); + var stream = gulpShopifySass(); + + stream.on('data', function(catScssFile) { + should.exist(catScssFile); + should.exist(catScssFile.path); + should.exist(catScssFile.relative); + should.exist(catScssFile.contents); + should.equal(path.basename(catScssFile.path), 'import.liquid.cat.scss.liquid'); + String(catScssFile.contents).should.equal( + fs.readFileSync(path.join(__dirname, 'fixtures', 'expected', 'import.liquid.cat.scss.liquid'), 'utf8') + ); + done(); + }); + + stream.write(sassFile); + }); + + it('do not import .scss.liquid if .scss exist', function(done) { + var sassFile = createVinyl('extensionOverride.scss'); + var stream = gulpShopifySass(); + + stream.on('data', function(catScssFile) { + should.exist(catScssFile); + should.exist(catScssFile.path); + should.exist(catScssFile.relative); + should.exist(catScssFile.contents); + should.equal(path.basename(catScssFile.path), 'extensionOverride.cat.scss.liquid'); + String(catScssFile.contents).should.equal( + fs.readFileSync(path.join(__dirname, 'fixtures', 'expected', 'extentionOverride.cat.scss.liquid'), 'utf8') + ); + done(); + }); + + stream.write(sassFile); }); - }); -}); +}); \ No newline at end of file