diff --git a/index.js b/index.js index 33c51c3..716ceba 100644 --- a/index.js +++ b/index.js @@ -13,6 +13,8 @@ const getStdin = require('get-stdin') const postcss = require('postcss') const postcssrc = require('postcss-load-config') +const getDependencyMessages = require('./lib/get-dependency-messages.js') + const logo = ` /|\\ // // @@ -91,32 +93,36 @@ getConfig({}, argv.config) console.warn('No files passed, reading from stdin') return ['-'] }) - .then(files => { - if (!files || !files.length) throw new Error('You must pass a valid list of files to parse') - if (files.length > 1 && argv.output) throw new Error('Must use --dir or --replace with multiple input files') + .then(expandedInput => { + input = expandedInput + if (!input || !input.length) throw new Error('You must pass a valid list of files to parse') + if (input.length > 1 && argv.output) throw new Error('Must use --dir or --replace with multiple input files') - return processFiles(files) + return processFiles(input) }) - .then(function () { + .then(function (results) { if (argv.watch) { spinner.text = 'Waiting for file changes...' let watcher = chokidar - .watch(input) + .watch(input.concat(getDependencyMessages(results))) watcher .add(config.file) .on('ready', (file) => spinner.start()) .on('change', (file) => { - if (file === config.file) { - return Promise.all([globber(input), getConfig()]) - .then(arr => processFiles(arr[0])) + // If this is not a direct input file, process all: + if (input.indexOf(file) === -1) { + return getConfig() + .then(() => processFiles(input)) + .then(results => watcher.add(getDependencyMessages(results))) .catch(error) } - spinner.text = `Processing ${chalk.green(`${file}`)}` - getConfig().then(() => processFiles(file, watcher)) - .then(() => { + getConfig() + .then(() => processFiles(file)) + .then(result => { + watcher.add(getDependencyMessages(result)) spinner.text = 'Waiting for file changes...' spinner.start() }) @@ -126,7 +132,7 @@ getConfig({}, argv.config) }) .catch(error) -function processCSS (css, filename, watcher) { +function processCSS (css, filename) { var spinner = ora(`Processing ${filename || 'your CSS'}`) spinner.start() @@ -141,12 +147,6 @@ function processCSS (css, filename, watcher) { return postcss(config.plugins).process(css, options) .then(result => { - if (watcher) { - result.messages - .filter((msg) => msg.type === 'dependency' ? msg : '') - .forEach((dep) => watcher.add(dep)) - } - if (result.messages.some(msg => msg.type === 'warning')) spinner.fail() var tasks = [fs.outputFile(options.to, result.css)] @@ -161,16 +161,16 @@ function processCSS (css, filename, watcher) { }) } -function processFiles (files, watcher) { +function processFiles (files) { if (typeof files === 'string') files = [files] return Promise.all(files.map(file => { // Read from stdin if (file === '-') { return getStdin() - .then(css => processCSS(css, undefined, watcher)) + .then(css => processCSS(css)) } return fs.readFile(file) - .then(css => processCSS(css, file, watcher)) + .then(css => processCSS(css, file)) })) } diff --git a/lib/get-dependency-messages.js b/lib/get-dependency-messages.js new file mode 100644 index 0000000..f1032ea --- /dev/null +++ b/lib/get-dependency-messages.js @@ -0,0 +1,12 @@ +module.exports = function (results) { + if (!Array.isArray(results)) results = [results] + let arr = [] + + results + .forEach(result => { + result.messages + .filter(msg => msg.type === 'dependency' ? msg : '') + .forEach(dep => arr.push(dep.file)) + }) + return arr +} diff --git a/test/watch.js b/test/watch.js index f808695..90e68e1 100644 --- a/test/watch.js +++ b/test/watch.js @@ -147,3 +147,73 @@ test.cb('--watch watches postcss.config.js', function (t) { // Timeout: setTimeout(() => t.end('test timeout'), 50000) }) + +test.cb('--watch watches dependencies', function (t) { + var cp + + t.plan(2) + + createEnv('', ['*a-red.css']) + .then(dir => { + // Init watcher: + var watcher = chokidar.watch('.', { + cwd: dir, + ignoreInitial: true, + awaitWriteFinish: true + }) + + // On the first output: + watcher.on('add', p => { + // Assert, then change the source file + if (p === 'out.css') { + isEqual(p, 'test/fixtures/a-red.css') + .then(() => read('test/fixtures/a-blue.css')) + .then(css => fs.writeFile(path.join(dir, 'a-red.css'), css)) + .catch(done) + } + }) + + // When the change is picked up: + watcher.on('change', p => { + if (p === 'out.css') { + isEqual(p, 'test/fixtures/a-blue.css') + .then(() => done()) + .catch(done) + } + }) + + // Start postcss-cli: + watcher.on('ready', () => { + cp = execFile( + path.resolve('bin/postcss'), + [ + 'imports-a-red.css', + '-o', 'out.css', + '-u', 'postcss-import', + '-w', + '--no-map' + ], + {cwd: dir} + ) + cp.on('error', t.end) + cp.on('exit', code => { if (code) t.end(code) }) + }) + + // Helper functions: + function isEqual (p, expected) { + return Promise.all([read(path.join(dir, p)), read(expected)]) + .then(([a, e]) => t.is(a, e)) + } + + function done (err) { + try { + cp.kill() + } catch (e) {} + t.end(err) + } + }) + .catch(t.end) + + // Timeout: + setTimeout(() => t.end('test timeout'), 50000) +})