var fs = require('fs'); var path = require('path'); var less = require('less'); var through2 = require('through2'); var replaceExt = require('replace-ext'); var assign = require('object-assign'); var applySourceMap = require('vinyl-sourcemaps-apply'); var PluginError = require('plugin-error'); function inlineSources(map) { if (map.sourcesContent) { return Promise.resolve(map); } return Promise.all( map.sources.map(function (source) { return new Promise(function (resolve, reject) { fs.readFile(source, 'utf8', function (err, data) { if (err) { reject(err); } else { resolve(data); } }); }); }) ).then( function (contents) { map.sourcesContent = contents; return map; }, function () { return map; } ); } function renderLess(str, opts) { return new Promise(function (resolve, reject) { less.render(str, opts, function (err, res) { if (err) { reject(err); } else { var obj = { result: res.css, imports: res.imports, }; if (opts.sourceMap && res.map) { obj.sourcemap = JSON.parse(res.map); inlineSources(obj.sourcemap).then(function (map) { obj.sourcemap = map; resolve(obj); }); } else { resolve(obj); } } }); }); } module.exports = function (options) { // Mixes in default options. var opts = assign({}, { compress: false, paths: [] }, options); return through2.obj(function (file, enc, cb) { if (file.isNull()) { return cb(null, file); } if (file.isStream()) { return cb(new PluginError('gulp-less', 'Streaming not supported')); } var str = file.contents.toString(); // Injects the path of the current file opts.filename = file.path; // Bootstrap source maps if (file.sourceMap || opts.sourcemap) { opts.sourceMap = true; } renderLess(str, opts).then(function(res) { file.contents = Buffer.from(res.result); file.path = replaceExt(file.path, '.css'); if (res.sourcemap) { res.sourcemap.file = file.relative; res.sourcemap.sources = res.sourcemap.sources.map(function (source) { return path.relative(file.base, source); }); applySourceMap(file, res.sourcemap); } return file; }).then(function(file) { cb(null, file); }).catch(function(err) { // Convert the keys so PluginError can read them err.lineNumber = err.line; err.fileName = err.filename; // Add a better error message err.message = err.message + ' in file ' + err.fileName + ' line no. ' + err.lineNumber; return cb(new PluginError('gulp-less', err)); }); }); };