1 var pkg = require('../package');
3 module.exports = function (grunt) {
6 var dev = !!grunt.option('dev');
7 var path, cssPath, libraries, librariesCache, librariesPath, versions, latestVersion;
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);
16 if (backup && backup !== true) {
17 file = resolveVariables(backup, true);
18 if (file) grunt.verbose.writeln("Using: " + file);
22 else if (backup === true) grunt.verbose.ok();
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`.');
37 libraries = grunt.file.readJSON(librariesCache);
38 if (!libraries.bootstrap || !libraries.bootswatch) {
39 return grunt.fail.fatal('Invalid libraries cache. Please run `grunt sync`.');
42 versions = Object.keys(libraries.bootstrap);
43 latestVersion = [].concat(versions).pop();
44 grunt.config.set('latestVersion', latestVersion);
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');
56 new LessPluginCleanCSS({
59 new LessPluginAutoPrefix({
73 var queue = require('queue')({concurrency: 1, timeout: 60000});
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);
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);
102 filename: outputFile,
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') + '"'
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) {
121 grunt.log.writeln('Compiled '.green + path.join(version, fileName).white.bold);
122 grunt.file.write(outputFile, output.css);
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);
131 return grunt.fail.fatal(e);
135 })(library, Object.keys(libraries[library]), version, libraries[library][version][i], total);
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.'));
148 // Run necessary sub-tasks.
149 var subtask = (dev ? 'dev' : 'css');