├── test ├── test-scss │ ├── recursive-folder │ │ ├── f1.scss │ │ ├── f2.scss │ │ └── nested-folder │ │ │ └── f3.scss │ ├── app.scss │ ├── duplicate-folder │ │ ├── f1.scss │ │ ├── f2.scss │ │ └── f3.scss │ ├── recursive.scss │ ├── import-folder │ │ ├── f1.scss │ │ └── f2.scss │ ├── duplicates.scss │ ├── single-double-quotes.scss │ └── duplicates2.scss └── test.js ├── .travis.yml ├── .gitignore ├── package.json ├── README.md ├── LICENSE └── index.js /test/test-scss/recursive-folder/f1.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/test-scss/recursive-folder/f2.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/test-scss/recursive-folder/nested-folder/f3.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/test-scss/app.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | @import "import-folder/*"; 4 | 5 | -------------------------------------------------------------------------------- /test/test-scss/duplicate-folder/f1.scss: -------------------------------------------------------------------------------- 1 | h3 { 2 | background-color: red; 3 | } -------------------------------------------------------------------------------- /test/test-scss/duplicate-folder/f2.scss: -------------------------------------------------------------------------------- 1 | h4 { 2 | background-color: red; 3 | } -------------------------------------------------------------------------------- /test/test-scss/duplicate-folder/f3.scss: -------------------------------------------------------------------------------- 1 | h4 { 2 | background-color: red; 3 | } -------------------------------------------------------------------------------- /test/test-scss/recursive.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | @import "recursive-folder/*"; 4 | 5 | -------------------------------------------------------------------------------- /test/test-scss/import-folder/f1.scss: -------------------------------------------------------------------------------- 1 | 2 | h3 { 3 | background-color: red; 4 | } 5 | -------------------------------------------------------------------------------- /test/test-scss/import-folder/f2.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | h4 { 4 | background-color: red; 5 | } 6 | -------------------------------------------------------------------------------- /test/test-scss/duplicates.scss: -------------------------------------------------------------------------------- 1 | @import "duplicate-folder/f1"; 2 | @import "duplicate-folder/*"; -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5.0" 4 | - "4.0" 5 | - "0.12" 6 | - "0.10" 7 | -------------------------------------------------------------------------------- /test/test-scss/single-double-quotes.scss: -------------------------------------------------------------------------------- 1 | 2 | @import "import-folder/*"; 3 | @import "recursive-folder/nested-folder/*"; -------------------------------------------------------------------------------- /test/test-scss/duplicates2.scss: -------------------------------------------------------------------------------- 1 | @import "duplicate-folder/f1"; 2 | @import "duplicate-folder/f2"; 3 | @import "duplicate-folder/*"; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | # Mac binary 31 | .DS_Store 32 | 33 | # Sublime 34 | *.sublime-project 35 | *.sublime-workspace -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-sass-bulk-import", 3 | "version": "1.0.1", 4 | "description": "import directories in your SCSS", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:mathisonian/gulp-sass-bulk-import.git" 12 | }, 13 | "keywords": [ 14 | "gulpplugin", 15 | "scss", 16 | "sass", 17 | "glob", 18 | "import", 19 | "directory", 20 | "bulk", 21 | "import", 22 | "sass" 23 | ], 24 | "author": "Matthew Conlen", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/mathisonian/gulp-sass-bulk-import/issues" 28 | }, 29 | "homepage": "https://github.com/mathisonian/gulp-sass-bulk-import", 30 | "dependencies": { 31 | "glob": "^4.0.6", 32 | "through2": "^0.6.3", 33 | "vinyl-fs": "^0.3.9" 34 | }, 35 | "devDependencies": { 36 | "expect.js": "^0.3.1", 37 | "mocha": "^1.21.4" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gulp-sass-bulk-import 2 | ===================== 3 | 4 | gulp task to allow importing directories in your SCSS 5 | 6 | [![Build Status](https://travis-ci.org/mathisonian/gulp-sass-bulk-import.svg?branch=master)](https://travis-ci.org/mathisonian/gulp-sass-bulk-import) 7 | 8 | ## installation 9 | 10 | ``` 11 | npm install --save-dev gulp-sass-bulk-import 12 | ``` 13 | 14 | 15 | ## usage 16 | 17 | 18 | #### in your .scss file 19 | 20 | ```scss 21 | 22 | @import "some/path/*"; 23 | 24 | // becomes 25 | // @import "some/path/file1.scss"; 26 | // @import "some/path/file2.scss"; 27 | // ... 28 | 29 | ``` 30 | 31 | #### in your gulpfile 32 | 33 | ```js 34 | var bulkSass = require('gulp-sass-bulk-import'); 35 | 36 | gulp.task('css', function() { 37 | return gulp 38 | .src(srcDir + 'stylesheets/app.scss') 39 | .pipe(bulkSass()) 40 | .pipe( 41 | sass({ 42 | includePaths: ['src/stylesheets'] 43 | })) 44 | .pipe( gulp.dest('./public/css/') ); 45 | }); 46 | ``` 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Matthew Conlen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | var through = require('through2'); 7 | var glob = require('glob'); 8 | 9 | module.exports = function() { 10 | 11 | var process = function(filename) { 12 | var replaceString = ''; 13 | 14 | if (fs.statSync(filename).isDirectory()) { 15 | // Ignore directories start with _ 16 | if (path.basename(filename).substring(0, 1) == '_') return ''; 17 | 18 | fs.readdirSync(filename).forEach(function (file) { 19 | replaceString += process(filename + '/' + file); 20 | }); 21 | return replaceString; 22 | } else { 23 | if (filename.substr(-4).match(/sass|scss/i)) { 24 | return '@import "' + filename + '";\n' 25 | } else { 26 | return ''; 27 | } 28 | } 29 | } 30 | 31 | var transform = function(file, env, cb) { 32 | 33 | // find all instances matching 34 | var contents = file.contents.toString('utf-8'); 35 | 36 | var reg = /@import\s+[\"']([^\"']*\*[^\"']*)[\"'];?/; // See: https://regex101.com/r/vL2pW5/1 37 | var regExcludeFiles = /^(?!\/\/)\s*?@import\s+[\"'][^\"'*]*[\"']\s*;?/gm; // See: https://regex101.com/r/aU3cA9/2 38 | var excludedFiles = contents.match(regExcludeFiles) || []; 39 | 40 | // console.log(excludedFiles); 41 | 42 | var directory = path.dirname(file.path); 43 | var result; 44 | 45 | while((result = reg.exec(contents)) !== null) { 46 | 47 | var sub = result[0]; 48 | var globName = result[1]; 49 | 50 | var files = glob.sync(path.join(directory, globName)); 51 | var replaceString = ''; 52 | 53 | files.forEach(function(filename){ 54 | var shouldReplace = !excludedFiles.some(function(excludedFile){ 55 | excludedFile = excludedFile.replace(/^\s*@import\s+/, '').replace(/^["']/g, '').replace(/["']\s*;?$/,''); 56 | var pathEndsWith = new RegExp(excludedFile + '$'); 57 | return ~filename.replace(/\.(scss|sass)$/, '').search(pathEndsWith); 58 | }); 59 | 60 | if(shouldReplace){ 61 | replaceString += process(filename); 62 | } 63 | 64 | }); 65 | contents = contents.replace(sub, replaceString); 66 | } 67 | 68 | file.contents = new Buffer(contents); 69 | cb(null, file); 70 | }; 71 | return through.obj(transform); 72 | }; 73 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var expect = require('expect.js'); 2 | var vinyl = require('vinyl-fs'); 3 | var bulkSass = require('..'); 4 | 5 | 6 | describe('gulp-sass-glob-import', function() { 7 | 8 | it('should parse a single directory', function(done) { 9 | var equalString = '@import "' + __dirname + '/test-scss/import-folder/f1.scss' + '";\n'; 10 | equalString += '@import "' + __dirname + '/test-scss/import-folder/f2.scss' + '";\n'; 11 | 12 | vinyl 13 | .src(__dirname + '/test-scss/app.scss') 14 | .pipe(bulkSass()) 15 | .on('data', function(file) { 16 | expect(file.contents.toString('utf-8').trim()).to.equal(equalString.trim()); 17 | }) 18 | .on('end', function() { 19 | done(); 20 | }); 21 | }); 22 | 23 | 24 | it('should parse a directory recursively', function(done) { 25 | var equalString = '@import "' + __dirname + '/test-scss/recursive-folder/f1.scss' + '";\n'; 26 | equalString += '@import "' + __dirname + '/test-scss/recursive-folder/f2.scss' + '";\n'; 27 | equalString += '@import "' + __dirname + '/test-scss/recursive-folder/nested-folder/f3.scss' + '";\n'; 28 | 29 | vinyl 30 | .src(__dirname + '/test-scss/recursive.scss') 31 | .pipe(bulkSass()) 32 | .on('data', function(file) { 33 | expect(file.contents.toString('utf-8').trim()).to.equal(equalString.trim()); 34 | }) 35 | .on('end', function() { 36 | done(); 37 | }); 38 | }); 39 | 40 | 41 | it('should handle single and double quotes', function(done) { 42 | var equalString = '@import "' + __dirname + '/test-scss/import-folder/f1.scss' + '";\n'; 43 | equalString += '@import "' + __dirname + '/test-scss/import-folder/f2.scss' + '";\n\n'; 44 | equalString += '@import "' + __dirname + '/test-scss/recursive-folder/nested-folder/f3.scss' + '";\n'; 45 | 46 | 47 | vinyl 48 | .src(__dirname + '/test-scss/single-double-quotes.scss') 49 | .pipe(bulkSass()) 50 | .on('data', function(file) { 51 | expect(file.contents.toString('utf-8').trim()).to.equal(equalString.trim()); 52 | }) 53 | .on('end', function() { 54 | done(); 55 | }); 56 | }); 57 | 58 | it('should not include a stylesheet more than once', function(done){ 59 | var equalString = '@import "duplicate-folder/f1";\n'; 60 | equalString += '@import "' + __dirname + '/test-scss/duplicate-folder/f2.scss";\n'; 61 | equalString += '@import "' + __dirname + '/test-scss/duplicate-folder/f3.scss";\n'; 62 | 63 | vinyl 64 | .src(__dirname + '/test-scss/duplicates.scss') 65 | .pipe(bulkSass()) 66 | .on('data', function(file){ 67 | expect(file.contents.toString('utf-8').trim()).to.equal(equalString.trim()); 68 | }) 69 | .on('end', function(){ 70 | done(); 71 | }); 72 | }); 73 | 74 | it('alternate: should not include a stylesheet more than once', function(done){ 75 | var equalString = '@import "duplicate-folder/f1"' + ';\n'; 76 | equalString += '@import "duplicate-folder/f2"' + ';\n'; 77 | equalString += '@import "' + __dirname + '/test-scss/duplicate-folder/f3.scss' + '";\n'; 78 | 79 | vinyl 80 | .src(__dirname + '/test-scss/duplicates2.scss') 81 | .pipe(bulkSass()) 82 | .on('data', function(file){ 83 | expect(file.contents.toString('utf-8').trim()).to.equal(equalString.trim()); 84 | }) 85 | .on('end', function(){ 86 | done(); 87 | }); 88 | }); 89 | 90 | }); --------------------------------------------------------------------------------