diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..a3ca543 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ + + +- `prettier-eslint-cli` version: +- `prettier` version: +- `eslint` version: + +Relevant code/config. + +```javascript + +``` + +What you did: + + + +What happened: + + + +Reproduction: + + + +-- paste your link here -- + +Problem description: + + + +Suggested solution: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..efc9a8d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ + + + +**What**: + + +**Why**: + + +**How**: + + + diff --git a/src/__snapshots__/uncaught-exception-handler.test.js.snap b/src/__snapshots__/uncaught-exception-handler.test.js.snap new file mode 100644 index 0000000..bfdb4b6 --- /dev/null +++ b/src/__snapshots__/uncaught-exception-handler.test.js.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`logs a check for trace 1`] = ` +"There has been an unknown error when running the prettier-eslint CLI. If it's unclear to you what went wrong, then try this: + ✅ Run the script again with the LOG_LEVEL environment variable set to \\"trace\\" + 2. Search existing issues on GitHub: https://github.com/prettier/prettier-eslint-cli/issues?utf8=%E2%9C%93&q=my%20error + 3. Make a minimal reproduction in a totally separate repository. You can fork this one: https://github.com/kentcdodds/prettier-eslint-cli-repro + 4. Post an issue with a link to your reproduction to the issues on GitHub: https://github.com/prettier/prettier-eslint-cli/issues/new" +`; + +exports[`logs all options 1`] = ` +"There has been an unknown error when running the prettier-eslint CLI. If it's unclear to you what went wrong, then try this: + 1. Run the script again with the LOG_LEVEL environment variable set to \\"trace\\" + 2. Search existing issues on GitHub: https://github.com/prettier/prettier-eslint-cli/issues?utf8=%E2%9C%93&q=my%20error + 3. Make a minimal reproduction in a totally separate repository. You can fork this one: https://github.com/kentcdodds/prettier-eslint-cli-repro + 4. Post an issue with a link to your reproduction to the issues on GitHub: https://github.com/prettier/prettier-eslint-cli/issues/new" +`; diff --git a/src/add-exception-handler.js b/src/add-exception-handler.js new file mode 100644 index 0000000..dcaa57a --- /dev/null +++ b/src/add-exception-handler.js @@ -0,0 +1,4 @@ +/* istanbul ignore-next */ +import onUncaughtException from './uncaught-exception-handler' + +process.on('uncaughtException', onUncaughtException) diff --git a/src/index.js b/src/index.js index 4a2c3fc..2aff9b9 100755 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,15 @@ #!/usr/bin/env node +// eslint-disable-next-line import/no-unassigned-import +import './add-exception-handler' // want to do this first +import getLogger from 'loglevel-colored-level-prefix' import parser from './parser' import formatFiles from './format-files' -const argv = parser.parse(process.argv.slice(2)) +const logger = getLogger({prefix: 'prettier-eslint-cli'}) +const args = process.argv.slice(2) + +logger.trace('Parsing args: ', args) +const argv = parser.parse(args) formatFiles(argv) diff --git a/src/parser.js b/src/parser.js index efafa1e..49133eb 100644 --- a/src/parser.js +++ b/src/parser.js @@ -1,4 +1,5 @@ import path from 'path' +import getLogger from 'loglevel-colored-level-prefix' import findUp from 'find-up' import yargs from 'yargs' import {oneLine} from 'common-tags' @@ -7,6 +8,8 @@ import camelcaseKeys from 'camelcase-keys' import chalk from 'chalk' import boolify from 'boolify' +const logger = getLogger({prefix: 'prettier-eslint-cli'}) + const parser = yargs .usage('Usage: $0 ... [--option-1 option-1-value --option-2]') .help('h') @@ -40,10 +43,10 @@ const parser = yargs }, ignore: { describe: oneLine` - pattern(s) you wish to ignore - (can be used multiple times - and includes **/node_modules/** automatically) - `, + pattern(s) you wish to ignore + (can be used multiple times + and includes **/node_modules/** automatically) + `, coerce: arrify, }, 'log-level': { @@ -59,9 +62,10 @@ const parser = yargs }, prettier: { describe: oneLine` - Prettier configuration options - to be passed to prettier-eslint - using dot-notation`, + Prettier configuration options + to be passed to prettier-eslint + using dot-notation + `, }, // TODO: if we allow people to to specify a config path, // we need to read that somehow. These can come invarious @@ -78,8 +82,10 @@ const parser = yargs } else { throw Error( chalk.red( - oneLine`You should use dot-notation with - the --prettier flag, for example, --prettier.singleQuote`, + oneLine` + You should use dot-notation with + the --prettier flag, for example, --prettier.singleQuote + `, ), ) } @@ -89,11 +95,18 @@ const parser = yargs export default parser function getPathInHostNodeModules(module) { + logger.debug(`Looking for a local installation of the module "${module}"`) const modulePath = findUp.sync(`node_modules/${module}`) if (modulePath) { return modulePath } + logger.debug( + oneLine` + Local installation of "${module}" not found, + looking again starting in "${__dirname}" + `, + ) return findUp.sync(`node_modules/${module}`, {cwd: __dirname}) } diff --git a/src/uncaught-exception-handler.js b/src/uncaught-exception-handler.js new file mode 100644 index 0000000..9e040d7 --- /dev/null +++ b/src/uncaught-exception-handler.js @@ -0,0 +1,42 @@ +import {oneLine, oneLineTrim} from 'common-tags' +import getLogger from 'loglevel-colored-level-prefix' + +const logger = getLogger({prefix: 'prettier-eslint-cli'}) + +export default onUncaughtException + +function onUncaughtException(err) { + const level = logger.getLevel() + const isTrace = level === 0 + const traceResolution = oneLine` + Run the script again with the LOG_LEVEL + environment variable set to "trace" + ` + const resolutionSteps = [ + `${isTrace ? '✅ ' : '1.'} ${traceResolution}`, + oneLine` + 2. Search existing issues on GitHub: + ${oneLineTrim` + https://github.com/prettier/prettier-eslint-cli/issues + ?utf8=%E2%9C%93&q=${encodeURIComponent(err.message)} + `} + `, + oneLine` + 3. Make a minimal reproduction in a totally separate repository. + You can fork this one: + https://github.com/kentcdodds/prettier-eslint-cli-repro + `, + oneLine` + 4. Post an issue with a link to your reproduction to the issues + on GitHub: https://github.com/prettier/prettier-eslint-cli/issues/new + `, + ].join('\n ') + logger.error( + oneLine` + There has been an unknown error when running the prettier-eslint CLI. + If it's unclear to you what went wrong, then try this: + `, + `\n ${resolutionSteps}`, + ) + throw err +} diff --git a/src/uncaught-exception-handler.test.js b/src/uncaught-exception-handler.test.js new file mode 100644 index 0000000..540dde0 --- /dev/null +++ b/src/uncaught-exception-handler.test.js @@ -0,0 +1,58 @@ +import getLoggerMock from 'loglevel-colored-level-prefix' +import onUncaughtException from './uncaught-exception-handler' + +jest.mock('loglevel-colored-level-prefix', () => { + const logger = {} + const __mock__ = {logger, level: 4, resetAll} + const getLogger = jest.fn(() => resetAll()) + getLogger.__mock__ = __mock__ + return getLogger + + function resetAll() { + getLogger.mockClear() + Object.assign(logger, { + getLevel: jest.fn(() => getLogger.__mock__.level), + trace: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }) + return logger + } +}) + +beforeEach(() => { + getLoggerMock.__mock__.resetAll() +}) + +test('logs all options', () => { + const logger = getLoggerMock() + runWithCatch(new Error('my error')) + expect(logger.error).toHaveBeenCalledTimes(1) + const errorLog = logger.error.mock.calls[0].join(' ') + expect(errorLog).toMatchSnapshot() +}) + +test('logs a check for trace', () => { + getLoggerMock.__mock__.level = 0 + const logger = getLoggerMock() + runWithCatch(new Error('my error')) + expect(logger.error).toHaveBeenCalledTimes(1) + const errorLog = logger.error.mock.calls[0].join(' ') + expect(errorLog).toContain('✅') + expect(errorLog).toMatchSnapshot() +}) + +test('re-throws the given error', () => { + const myError = new Error('my error') + expect(() => onUncaughtException(myError)).toThrow(myError) +}) + +function runWithCatch(...args) { + try { + onUncaughtException(...args) + } catch (e) { + // ignore + } +}