From 185908026213b584bce581153e246ed73a115a52 Mon Sep 17 00:00:00 2001 From: Ryan Zimmerman Date: Thu, 20 Aug 2026 13:10:06 -0400 Subject: [PATCH 1/3] BREAKING: exit on all types of configuration errors in watch mode --- index.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 7294893..82b92e3 100755 --- a/index.js +++ b/index.js @@ -45,10 +45,10 @@ async function buildCliConfig() { try { return (await import(plugin)).default() } catch (e) { - const msg = e.message || `Cannot find module '${plugin}'` + const msg = e.message || `Unknown error in '${plugin}'` let prefix = msg.includes(plugin) ? '' : ` (${plugin})` if (e.name && e.name !== 'Error') prefix += `: ${e.name}` - return error(`Plugin Error${prefix}: ${msg}'`) + error(`Plugin Error${prefix}: ${msg}'`) } }), ) @@ -85,8 +85,6 @@ buildCliConfig() .then(() => { if (argv.watch && !(argv.output || argv.replace || argv.dir)) { error('Cannot write to stdout in watch mode') - // Need to explicitly exit here, since error() doesn't exit in watch mode - process.exit(1) } if (input && input.length) { @@ -158,15 +156,14 @@ buildCliConfig() return files([...new Set(recompile)]) .then((results) => watcher.add(dependencies(results))) .then(printMessage) - .catch(error) + .catch((err) => { + // Watch mode shouldn't exit on file processing error + error(err, argv.watch) + }) }) } }) - .catch((err) => { - error(err) - - process.exit(1) - }) + .catch(error) function rc(ctx, path) { if (argv.use) return Promise.resolve(cliConfig) @@ -331,7 +328,7 @@ function printVerbose(message) { if (argv.verbose) console.warn(message) } -function error(err) { +function error(err, dontExit) { // Seperate error from logging output if (argv.verbose) console.error() @@ -342,8 +339,7 @@ function error(err) { } else { console.error(err) } - // Watch mode shouldn't exit on error - if (argv.watch) return + if (dontExit) return process.exit(1) } From d983307eb47ccb4b5f670d9939f332c097bba3ca Mon Sep 17 00:00:00 2001 From: Ryan Zimmerman Date: Thu, 20 Aug 2026 14:05:10 -0400 Subject: [PATCH 2/3] Test errors in watch mode --- test/error.js | 101 +++++++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 42 deletions(-) diff --git a/test/error.js b/test/error.js index 8c76a47..427f177 100644 --- a/test/error.js +++ b/test/error.js @@ -3,13 +3,68 @@ import test from 'ava' import tmp from './helpers/tmp.js' import cli from './helpers/cli.js' -test('multiple input files && --output', (t) => { - return cli(['test/fixtures/*.css', '-o', tmp()]).then(({ error, code }) => { +// ensure that configuration errors are thrown in watch mode as well as normal mode +;[false, true].forEach((watch) => { + const prefix = watch ? 'watch mode: ' : '' + const additionalArgs = watch ? ['--watch'] : [] + + test(`${prefix}multiple input files && --output`, (t) => { + return cli(['test/fixtures/*.css', '-o', tmp(), ...additionalArgs]).then( + ({ error, code }) => { + t.is(code, 1, 'expected non-zero error code') + t.regex(error.toString(), /Input Error: Must use --dir or --replace/) + }, + ) + }) + + test(`${prefix}plugin not found`, (t) => { + return cli([ + 'test/fixtures/a.css', + '-u', + 'postcss-plugin', + '-o', + tmp(), + ...additionalArgs, + ]).then(({ error, code }) => { + t.is(code, 1, 'expected non-zero error code') + t.regex( + error.toString(), + /Plugin Error: Cannot find package 'postcss-plugin'/, + ) + }) + }) + + test(`${prefix}plugin throws on require`, (t) => { + return cli([ + 'test/fixtures/a.css', + '-u', + './test/fixtures/_bad-plugin.js', + '-o', + tmp(), + ...additionalArgs, + ]).then(({ error, code }) => { + t.is(code, 1, 'expected non-zero error code') + t.regex(error.toString(), /Plugin Error \(.*bad-plugin.js\): This fails/) + }) + }) + + test(`${prefix}fails on invalid explicit config`, async (t) => { + const output = tmp('output-ignore.css') + + const { stderr, code } = await cli([ + 'test/fixtures/a.css', + '-o', + output, + '--config', + '/foo/bar', + ...additionalArgs, + ]) t.is(code, 1, 'expected non-zero error code') - t.regex(error.toString(), /Input Error: Must use --dir or --replace/) + t.regex(stderr, /No PostCSS Config found/) }) }) +// These errors cannot occur in watch mode; watch mode does not support stdout test('multiple input files && writing to stdout', (t) => { return cli(['test/fixtures/*.css']).then(({ error, code }) => { t.is(code, 1, 'expected non-zero error code') @@ -27,31 +82,7 @@ test('--map && writing to stdout', (t) => { }) }) -test('plugin not found', (t) => { - return cli(['test/fixtures/a.css', '-u', 'postcss-plugin', '-o', tmp()]).then( - ({ error, code }) => { - t.is(code, 1, 'expected non-zero error code') - t.regex( - error.toString(), - /Plugin Error: Cannot find package 'postcss-plugin'/, - ) - }, - ) -}) - -test('plugin throws on require', (t) => { - return cli([ - 'test/fixtures/a.css', - '-u', - './test/fixtures/_bad-plugin.js', - '-o', - tmp(), - ]).then(({ error, code }) => { - t.is(code, 1, 'expected non-zero error code') - t.regex(error.toString(), /Plugin Error \(.*bad-plugin.js\): This fails/) - }) -}) - +// Watch mode does not exit on CssSyntaxError, this is tested in ./watch.js test('CssSyntaxError', (t) => { return cli(['test/fixtures/a.css', '--parser', 'sugarss', '-o', tmp()]).then( ({ error, code }) => { @@ -63,17 +94,3 @@ test('CssSyntaxError', (t) => { }, ) }) - -test('fails on invalid explicit config', async (t) => { - const output = tmp('output-ignore.css') - - const { stderr, code } = await cli([ - 'test/fixtures/a.css', - '-o', - output, - '--config', - '/foo/bar', - ]) - t.is(code, 1, 'expected non-zero error code') - t.regex(stderr, /No PostCSS Config found/) -}) From d2a6b1fc6039ef25d25c675b948c49dcd4261efc Mon Sep 17 00:00:00 2001 From: Ryan Zimmerman Date: Thu, 20 Aug 2026 14:20:04 -0400 Subject: [PATCH 3/3] Remove hanging single quote Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 82b92e3..3a9c0d7 100755 --- a/index.js +++ b/index.js @@ -48,7 +48,7 @@ async function buildCliConfig() { const msg = e.message || `Unknown error in '${plugin}'` let prefix = msg.includes(plugin) ? '' : ` (${plugin})` if (e.name && e.name !== 'Error') prefix += `: ${e.name}` - error(`Plugin Error${prefix}: ${msg}'`) + error(`Plugin Error${prefix}: ${msg}`) } }), )