90a8acd4b4b313197694ef3fceb1715bfa5491e4
[yaffs-website] / grunt / compile.js
1 var pkg = require('../package');
2
3 module.exports = function (grunt) {
4   'use strict';
5
6   var dev = !!grunt.option('dev');
7   var path, cssPath, libraries, librariesCache, librariesPath, versions, latestVersion;
8
9   // Helper function for falling back to a Bootstrap variables file.
10   var resolveVariables = function (file, backup) {
11     if (backup === true) grunt.verbose.write('Checking for backup variables file...');
12     if (!grunt.file.exists(path.join(librariesPath, file))) {
13       if (backup === true) grunt.verbose.warn();
14       grunt.verbose.writeln("Missing " + file);
15       file = false;
16       if (backup && backup !== true) {
17         file = resolveVariables(backup, true);
18         if (file) grunt.verbose.writeln("Using: " + file);
19       }
20       return file;
21     }
22     else if (backup === true) grunt.verbose.ok();
23     return file;
24   };
25
26   // Register the "compile" task.
27   grunt.registerTask('compile', 'Compiles the Drupal/Bootstrap override CSS files for the base theme.', function () {
28     var cwd = process.cwd();
29     path = require('path');
30     cssPath = path.join(cwd, pkg.paths.css);
31     librariesCache = path.join(cwd, pkg.caches.libraries);
32     librariesPath = path.join(cwd, pkg.paths.libraries);
33     if (!grunt.file.exists(librariesCache) || !grunt.file.isDir(librariesPath)) {
34       return grunt.fail.fatal('No libraries detected. Please run `grunt sync`.');
35     }
36
37     libraries = grunt.file.readJSON(librariesCache);
38     if (!libraries.bootstrap || !libraries.bootswatch) {
39       return grunt.fail.fatal('Invalid libraries cache. Please run `grunt sync`.');
40     }
41
42     versions = Object.keys(libraries.bootstrap);
43     latestVersion = [].concat(versions).pop();
44     grunt.config.set('latestVersion', latestVersion);
45
46     // Register a private sub-task. Doing this inside the main task prevents
47     // this private sub-task from being executed directly and also prevents it
48     // from showing up on the list of available tasks on --help.
49     grunt.registerTask('compile:overrides', function () {
50       var done = this.async();
51       var total = {count: 0};
52       var less = require('less');
53       var LessPluginAutoPrefix = require('less-plugin-autoprefix');
54       var LessPluginCleanCSS = require('less-plugin-clean-css');
55       var lessPlugins = [
56         new LessPluginCleanCSS({
57           advanced: true
58         }),
59         new LessPluginAutoPrefix({
60           browsers: [
61             "Android 2.3",
62             "Android >= 4",
63             "Chrome >= 20",
64             "Firefox >= 24",
65             "Explorer >= 8",
66             "iOS >= 6",
67             "Opera >= 12",
68             "Safari >= 6"
69           ],
70           map: true
71         })
72       ];
73       var queue = require('queue')({concurrency: 1, timeout: 60000});
74
75       // Iterate over libraries.
76       for (var library in libraries) {
77         if (!libraries.hasOwnProperty(library) || (dev && library !== 'bootstrap')) continue;
78         // Iterate over versions.
79         for (var version in libraries[library]) {
80           if (!libraries[library].hasOwnProperty(version) || (dev && version !== latestVersion)) continue;
81           // Iterate over themes.
82           for (var i = 0; i < libraries[library][version].length; i++) {
83             // Queue LESS compilations.
84             (function (library, versions, version, theme, total) {
85               queue.push(function (done) {
86                 var lessPaths = [path.join(librariesPath)];
87                 var latestVersion = [].concat(versions).pop();
88                 var latestVariables = path.join(latestVersion, 'bootstrap', 'less', 'variables.less');
89                 var latestMixins = path.join(latestVersion, 'bootstrap', 'less', 'mixins.less');
90                 var themeVariables = path.join(version, library, (library === 'bootstrap' ? 'less' : theme), 'variables.less');
91                 var backupVariables = path.join(version, 'bootstrap', 'less', 'variables.less');
92                 var fileName = (library === 'bootstrap' ? 'overrides.min.css' : 'overrides-' + theme + '.min.css');
93                 var outputFile = path.join(cssPath, version, fileName);
94
95                 // Resolve the variable files.
96                 latestVariables = resolveVariables(latestVariables);
97                 if (!latestVariables) return done(false);
98                 themeVariables = resolveVariables(themeVariables, backupVariables);
99                 if (!themeVariables) return grunt.fail.fatal("Unable to create: " + outputFile);
100
101                 var options = {
102                   filename: outputFile,
103                   paths: lessPaths,
104                   plugins: lessPlugins
105                 };
106                 var imports = [
107                   // First, import the latest bootstrap (missing variables).
108                   '@import "' + latestVariables + '"',
109                   // Then, override variables with theme.
110                   '@import "' + themeVariables + '"',
111                   // Then, import latest bootstrap mixins.
112                   '@import "' + latestMixins + '"',
113                   // Finally, import the base-theme overrides.
114                   '@import "' + path.join('starterkits', 'less', 'less', 'overrides.less') + '"'
115                 ];
116                 grunt.log.debug("\noptions: " + JSON.stringify(options, null, 2));
117                 grunt.log.debug(imports.join("\n"));
118                 less.render(imports.join(';') + ';', options)
119                   .then(function (output) {
120                     total.count++;
121                     grunt.log.writeln('Compiled '.green + path.join(version, fileName).white.bold);
122                     grunt.file.write(outputFile, output.css);
123                     done();
124                   }, function (e) {
125                     if (e.type === 'Parse') {
126                       grunt.log.error("File:\t".red + e.filename.red);
127                       grunt.log.error("Line:\t".red + [e.line, e.column].join(':').red);
128                       grunt.log.error("Code:\t".red + e.extract.join('').white.bold);
129                       grunt.log.writeln();
130                     }
131                     return grunt.fail.fatal(e);
132                   })
133                 ;
134               });
135             })(library, Object.keys(libraries[library]), version, libraries[library][version][i], total);
136           }
137         }
138       }
139
140       // Start LESS compilations queues.
141       queue.start(function (e) {
142         // Report how many files were compiled.
143         grunt.log.ok(grunt.util.pluralize(total.count, '1 file compiled./' + total.count + ' files compiled.'));
144         return done(e);
145       });
146     });
147
148     // Run necessary sub-tasks.
149     var subtask = (dev ? 'dev' : 'css');
150     grunt.task.run([
151       'clean:' + subtask,
152       'compile:overrides',
153       'csslint:' + subtask
154     ]);
155   });
156
157 };