1 var Stream = require('stream')
2 var postcss = require('postcss')
3 var applySourceMap = require('vinyl-sourcemaps-apply')
4 var gutil = require('gulp-util')
5 var path = require('path')
8 module.exports = withConfigLoader(function (loadConfig) {
10 var stream = new Stream.Transform({ objectMode: true })
12 stream._transform = function (file, encoding, cb) {
18 if (file.isStream()) {
19 return handleError('Streams are not supported!')
22 // Protect `from` and `map` if using gulp-sourcemaps
23 var isProtected = file.sourceMap
24 ? { from: true, map: true }
30 // Generate a separate source map for gulp-sourcemaps
31 , map: file.sourceMap ? { annotation: false } : false
35 .then(function (config) {
36 var configOpts = config.options || {}
37 // Extend the default options if not protected
38 for (var opt in configOpts) {
39 if (configOpts.hasOwnProperty(opt) && !isProtected[opt]) {
40 options[opt] = configOpts[opt]
44 file.relative + '\nCannot override ' + opt +
45 ' option, because it is required by gulp-sourcemaps'
49 return postcss(config.plugins || [])
50 .process(file.contents, options)
52 .then(handleResult, handleError)
54 function handleResult (result) {
56 var warnings = result.warnings().join('\n')
58 file.contents = new Buffer(result.css)
60 // Apply source map to the chain
62 map = result.map.toJSON()
63 map.file = file.relative
64 map.sources = [].map.call(map.sources, function (source) {
65 return path.join(path.dirname(file.relative), source)
67 applySourceMap(file, map)
71 gutil.log('gulp-postcss:', file.relative + '\n' + warnings)
74 setImmediate(function () {
79 function handleError (error) {
80 var errorOptions = { fileName: file.path, showStack: true }
81 if (error.name === 'CssSyntaxError') {
82 error = error.message + '\n\n' + error.showSourceCode() + '\n'
83 errorOptions.showStack = false
85 // Prevent stream’s unhandled exception from
86 // being suppressed by Promise
87 setImmediate(function () {
88 cb(new gutil.PluginError('gulp-postcss', error, errorOptions))
98 function withConfigLoader(cb) {
99 return function (plugins, options) {
100 if (Array.isArray(plugins)) {
101 return cb(function () {
102 return Promise.resolve({
107 } else if (typeof plugins === 'function') {
108 return cb(function (file) {
109 return Promise.resolve(plugins(file))
112 var postcssLoadConfig = require('postcss-load-config')
113 var contextOptions = plugins || {}
114 return cb(function(file) {
116 if (contextOptions.config) {
117 if (path.isAbsolute(contextOptions.config)) {
118 configPath = contextOptions.config
120 configPath = path.join(file.base, contextOptions.config)
123 configPath = file.dirname
125 return postcssLoadConfig(
127 , options: contextOptions