Skip to content

Commit b27643b

Browse files
bartvenemanclaude
andauthored
Breaking: Convert coverage-dir from flag to positional argument (#100)
* Convert coverage-dir from named option to positional argument Breaking change: `--coverage-dir=<path>` is replaced by a positional argument, e.g. `css-coverage ./coverage --min-coverage=0.8`. Updates argument parsing, validation error messages, tests, and help text. https://claude.ai/code/session_01HyhRGi53stHdRSZBkxTAeQ * Fix TS2345: restore non-null assertion on coverage_dir in return positionals[0] is string | undefined; the assertion is safe because we throw before reaching the return when coverage_dir is missing. https://claude.ai/code/session_01HyhRGi53stHdRSZBkxTAeQ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent dfc5876 commit b27643b

3 files changed

Lines changed: 23 additions & 25 deletions

File tree

src/cli/arguments.test.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,29 @@ import { test, expect } from '@playwright/test'
22
import { resolve } from 'node:path'
33
import { parse_arguments } from './arguments'
44

5-
test.describe('--coverage-dir', () => {
5+
test.describe('<coverage-dir>', () => {
66
let cov = '--min-coverage=1'
77

8-
test('missing --coverage-dir', () => {
8+
test('missing coverage-dir', () => {
99
expect(() => parse_arguments([cov])).toThrowError()
1010
})
1111

12-
test('empty --coverage-dir', () => {
13-
expect(() => parse_arguments([cov, '--coverage-dir'])).toThrowError()
14-
})
15-
16-
test('valid --coverage-dir=coverage', () => {
17-
let result = parse_arguments([cov, '--coverage-dir=coverage'])
12+
test('valid coverage-dir positional', () => {
13+
let result = parse_arguments(['coverage', cov])
1814
expect(result['coverage-dir']).toEqual(resolve('coverage'))
1915
})
2016

21-
test('path traversal --coverage-dir=../../etc', () => {
22-
expect(() => parse_arguments([cov, '--coverage-dir=../../etc'])).toThrowError()
17+
test('path traversal ../../etc', () => {
18+
expect(() => parse_arguments(['../../etc', cov])).toThrowError()
2319
})
2420

25-
test('path traversal --coverage-dir=../sibling', () => {
26-
expect(() => parse_arguments([cov, '--coverage-dir=../sibling'])).toThrowError()
21+
test('path traversal ../sibling', () => {
22+
expect(() => parse_arguments(['../sibling', cov])).toThrowError()
2723
})
2824
})
2925

3026
test.describe('--min-coverage', () => {
31-
let dir = '--coverage-dir=coverage'
27+
let dir = 'coverage'
3228

3329
test('missing --min-coverage', () => {
3430
expect(() => parse_arguments([dir])).toThrowError()
@@ -49,7 +45,7 @@ test.describe('--min-coverage', () => {
4945
})
5046

5147
test.describe('--min-file-coverage', () => {
52-
let args = ['--coverage-dir=coverage', '--min-coverage=1']
48+
let args = ['coverage', '--min-coverage=1']
5349

5450
test('missing --min-file-coverage defaults to 0', () => {
5551
let result = parse_arguments([...args])
@@ -71,7 +67,7 @@ test.describe('--min-file-coverage', () => {
7167
})
7268

7369
test.describe('--reporter', () => {
74-
let args = ['--coverage-dir=coverage', '--min-coverage=1']
70+
let args = ['coverage', '--min-coverage=1']
7571

7672
test('missing --reporter defaults to pretty', () => {
7773
let result = parse_arguments([...args])
@@ -98,7 +94,7 @@ test.describe('--reporter', () => {
9894
})
9995

10096
test.describe('--show-uncovered', () => {
101-
let args = ['--coverage-dir=coverage', '--min-coverage=1']
97+
let args = ['coverage', '--min-coverage=1']
10298

10399
test('missing --show-uncovered defaults to violations', () => {
104100
let result = parse_arguments([...args])

src/cli/arguments.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ export type CliArguments = {
1616
}
1717

1818
export function parse_arguments(args: string[]): CliArguments {
19-
let { values } = parseArgs({
19+
let { values, positionals } = parseArgs({
2020
args,
21+
allowPositionals: true,
2122
options: {
22-
'coverage-dir': { type: 'string' },
2323
'min-coverage': { type: 'string' },
2424
'min-file-coverage': { type: 'string', default: '0' },
2525
'show-uncovered': { type: 'string', default: 'violations' },
@@ -29,9 +29,9 @@ export function parse_arguments(args: string[]): CliArguments {
2929

3030
let issues: string[] = []
3131

32-
let coverage_dir = values['coverage-dir']
32+
let coverage_dir = positionals[0]
3333
if (!coverage_dir) {
34-
issues.push('--coverage-dir is required')
34+
issues.push('<coverage-dir> is required')
3535
} else {
3636
let resolved = resolve(coverage_dir)
3737
let cwd = process.cwd()

src/cli/help.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import { styleText } from 'node:util'
33
export function help() {
44
return `
55
${styleText(['bold'], 'USAGE')}
6-
$ css-coverage --coverage-dir=<dir> --min-coverage=<number> [options]
6+
$ css-coverage <coverage-dir> --min-coverage=<number> [options]
7+
8+
${styleText('bold', 'ARGUMENTS')}
9+
<coverage-dir> Where your Coverage JSON files are
710
811
${styleText('bold', 'OPTIONS')}
912
Required:
10-
--coverage-dir Where your Coverage JSON files are
1113
--min-coverage Minimum overall CSS coverage [0-1]
1214
1315
Optional:
@@ -26,12 +28,12 @@ Optional:
2628
2729
${styleText('bold', 'EXAMPLES')}
2830
${styleText('dim', '# analyze all .json files in ./coverage; require 80% overall coverage')}
29-
$ css-coverage --coverage-dir=./coverage --min-coverage=0.8
31+
$ css-coverage ./coverage --min-coverage=0.8
3032
3133
${styleText('dim', '# Require 50% coverage per file')}
32-
$ css-coverage --coverage-dir=./coverage --min-coverage=0.8 --min-file-coverage=0.5
34+
$ css-coverage ./coverage --min-coverage=0.8 --min-file-coverage=0.5
3335
3436
${styleText('dim', 'Report JSON')}
35-
$ css-coverage --coverage-dir=./coverage --min-coverage=0.8 --reporter=json
37+
$ css-coverage ./coverage --min-coverage=0.8 --reporter=json
3638
`.trim()
3739
}

0 commit comments

Comments
 (0)