diff --git a/packages/cli/src/commands/__tests__/lint.test.ts b/packages/cli/src/commands/__tests__/lint.test.ts index 240a547bc..54e0ac273 100644 --- a/packages/cli/src/commands/__tests__/lint.test.ts +++ b/packages/cli/src/commands/__tests__/lint.test.ts @@ -281,4 +281,15 @@ describe('lint', () => { expect(process.stderr.write).nthCalledWith(6, `Error #3: ${chalk.red('original exception')}\n`); }); + + it('writes output for dashed formats via --output. (#2926)', async () => { + (formatOutput as jest.Mock).mockReturnValue(''); + + await run( + `lint --format github-actions --format code-climate --output.github-actions ga.txt --output.code-climate cc.json ./__fixtures__/empty-oas2-document.json`, + ); + expect(writeOutput).toBeCalledTimes(2); + expect(writeOutput).toHaveBeenCalledWith('', 'ga.txt'); + expect(writeOutput).toHaveBeenCalledWith('', 'cc.json'); + }); }); diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts index 2528c4a80..27b9a53fc 100644 --- a/packages/cli/src/commands/lint.ts +++ b/packages/cli/src/commands/lint.ts @@ -1,7 +1,7 @@ import { DiagnosticSeverity, Dictionary } from '@stoplight/types'; import { isPlainObject } from '@stoplight/json'; import { getDiagnosticSeverity, IRuleResult } from '@stoplight/spectral-core'; -import { difference, isError, pick } from 'lodash'; +import { camelCase, difference, isError, pick } from 'lodash'; import type { ReadStream } from 'tty'; import type { CommandModule } from 'yargs'; import * as process from 'process'; @@ -114,6 +114,22 @@ const lintCommand: CommandModule = { alias: 'o', description: `where to output results, can be a single file name, multiple "output." or missing to print to stdout`, type: 'string', + // yargs camel-cases dotted keys, so `--output.github-actions` becomes + // `githubActions` (and may duplicate the original). Re-key the object by + // the canonical format names so dashed formats line up with `--format`. + coerce(value: unknown): unknown { + if (!isPlainObject(value)) return value; + const raw = value as Dictionary; + const normalized: Dictionary = {}; + for (const format of formatOptions) { + if (format in raw) { + normalized[format] = raw[format]; + } else if (camelCase(format) in raw) { + normalized[format] = raw[camelCase(format)]; + } + } + return normalized; + }, }, 'stdin-filepath': { description: 'path to a file to pretend that stdin comes from',