Initial commit
[yaffs-website] / node_modules / grunt-contrib-compass / tasks / lib / compass.js
1 'use strict';
2
3 exports.init = function (grunt) {
4   var fs = require('fs');
5   var tmp = require('tmp');
6   var dargs = require('dargs');
7   var path = require('path');
8   var async = require('async');
9   var onetime = require('onetime');
10   var whichSync = require('which').sync;
11
12
13   var exports = {};
14
15   function camelCaseToUnderscore(str) {
16     return str
17       .replace(/([a-z])([A-Z])/g, '$1_$2')
18       .toLowerCase();
19   }
20
21   // Extracts the options that cannot be used as CLI parameter but only
22   // as 'raw' arguments.
23   // Returns an object: {raw: str, options: []} with the raw string to be
24   // used to generate a config and the list of used options.
25   exports.extractRawOptions = function extractRawOptions(options) {
26     var raw = options.raw || '';
27     var supportedOptions = [
28       'css_path',
29       'http_stylesheets_path',
30       'sass_path',
31       'images_path',
32       'http_images_path',
33       'generated_images_dir',
34       'generated_images_path',
35       'http_generated_images_path',
36       'javascripts_path',
37       'http_javascripts_path',
38       'fonts_path',
39       'http_fonts_path',
40       'http_fonts_dir',
41       'extensions_dir',
42       'extension_path',
43       'cache_dir'
44     ];
45
46     var usedOptions = Object.keys(options).filter(function (option) {
47       var underscoredOption = camelCaseToUnderscore(option);
48       if (supportedOptions.indexOf(underscoredOption) >= 0) {
49         // naively escape single-quotes in the value
50         var value = options[option].replace(/'/g, '\\\'');
51         raw += underscoredOption + ' = \'' + value + '\'\n';
52         delete options[option];
53
54         return true;
55       } else if (underscoredOption === 'asset_cache_buster') {
56         // Special handling for asset_cache_buster as it doesn't take
57         // a string as argument, but either an inline-ruby block (which we don't
58         // support) or a `:none` symbol to disable it.
59         if (options[option] === false) {
60           raw += underscoredOption + ' :none' + '\n';
61         }
62         delete options[option];
63         return true;
64       } else if (underscoredOption === 'sprite_load_path') {
65         // Special handling for sprite_load_path as it doesn't take
66         // a string as argument, but an array or a string.
67         // Append the load paths in ruby via <<
68         // http://compass-style.org/blog/2012/02/01/compass-0-12-is-released/
69         var loadPath = options[option];
70         if (loadPath) {
71           loadPath = Array.isArray(loadPath) ? loadPath : [loadPath];
72           loadPath.forEach(function (path) {
73             // naively escape double-quotes in the value
74             path = path.replace(/"/g, '\\"');
75             raw += underscoredOption + ' << "' + path + '"\n';
76           });
77         }
78         delete options[option];
79         return true;
80       }
81     });
82
83     return {raw: raw, options: usedOptions};
84   };
85
86   // Create a function to add a banner, if requested through the options.
87   exports.buildBannerCallback = function (grunt, options) {
88     if (!options.specify || !options.banner) {
89       if (options.banner && !options.specify) {
90         grunt.warn('You can only use the `banner` option in combination with `specify.`');
91       }
92       // Return a no-op if specify or banner aren't set.
93       return function () {};
94     }
95
96     var srcFiles = grunt.file.expand({
97       filter: function (filePath) {
98         return path.basename(filePath)[0] !== '_';
99       }
100     }, options.specify);
101
102     var banner = options.banner;
103     delete options.banner;
104
105     var destFiles = srcFiles.map(function (filename) {
106       return filename.replace(options.sassDir, options.cssDir).replace(/\.(css\.)?(scss|sass)$/i, '.css');
107     });
108
109     return function () {
110       grunt.log.verbose.writeln('Writing CSS banners.');
111       async.map(destFiles, function (filename) {
112         grunt.log.verbose.writeln('Writing CSS banner for ' + filename);
113         var content = grunt.file.read(filename);
114         grunt.file.write(filename, banner + grunt.util.linefeed + content);
115       });
116     };
117   };
118
119   // Create a config file on the fly if there are arguments not supported as
120   // CLI, returns a function that runs within the temprorary context.
121   exports.buildConfigContext = function (options) {
122     var rawOptions = exports.extractRawOptions(options);
123     if (options.raw && options.config) {
124       grunt.warn('The options `raw` and `config` are mutually exclusive');
125     }
126
127     if (rawOptions.options.length > 0 && options.config) {
128       grunt.warn('The option `config` cannot be combined with ' +
129                        'these options: ' + rawOptions.options.join(', ') + '.');
130     }
131
132     return function configContext(cb) {
133       if (rawOptions.raw) {
134         tmp.setGracefulCleanup();
135         tmp.file(function (err, path, fd) {
136           if (err) {
137             return cb(err);
138           }
139
140           // Dynamically create config.rb as a tmp file for the `raw` content
141           fs.writeSync(fd, new Buffer(rawOptions.raw), 0, rawOptions.raw.length);
142           cb(null, path);
143         });
144       } else {
145         cb(null, null);
146       }
147     };
148   };
149
150   // build the array of arguments to build the compass command
151   exports.buildArgsArray = function (options) {
152     var args = ['compile'];
153     if (options.clean) {
154       args = ['clean'];
155     } else if (options.watch) {
156       args = ['watch'];
157     }
158
159     if (options.bundleExec) {
160       args.unshift(path.basename(whichSync('bundle')), 'exec', 'compass');
161     } else {
162       // Find the compass binary
163       args.unshift(path.basename(whichSync('compass')));
164     }
165
166     // add converted options
167     [].push.apply(args, dargs(options, [
168       'raw',
169       'clean',
170       'bundleExec',
171       'basePath',
172       'specify',
173       'watch'
174     ]));
175
176     if (grunt.option('no-color')) {
177       args.push('--boring');
178     }
179
180     var pushDoubleDash = onetime(function () {
181       args.push('--');
182     });
183
184     if (options.basePath) {
185       pushDoubleDash();
186       args.push(options.basePath);
187     }
188
189     if (options.specify) {
190       pushDoubleDash();
191       var files = grunt.file.expand({
192         filter: function (filePath) {
193           return path.basename(filePath)[0] !== '_';
194         }
195       }, options.specify);
196
197       if (files.length > 0) {
198         [].push.apply(args, files);
199       } else {
200         return grunt.log.writeln('`specify` option used, but no files were found.');
201       }
202     }
203
204     return args;
205   };
206
207   return exports;
208 };