Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 23 additions & 21 deletions src/cli/reporters/pretty.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ test.describe('with --min-file-line-coverage', () => {
expect(lines[4]).toEqual(lines[0])
})
test('shows file name', () => {
expect(lines[1]).toEqual('example.com')
expect(lines[1]).toEqual('File: example.com')
})
test('shows coverage info', () => {
expect(lines[2]).toEqual('Coverage: 42.11%, 8/19 lines covered')
Expand All @@ -262,29 +262,31 @@ test.describe('with --min-file-line-coverage', () => {
expect(snapshot).toEqual(
`
────────────────────────────────────────────────────────────
example.com
File: example.com
Coverage: 42.11%, 8/19 lines covered
Tip: cover 11 more lines to meet the file threshold of 100%
────────────────────────────────────────────────────────────
1 ━ a {
2 ━ color: red;
3 ━ }
4 │
5 │ a1 {
6 │ color: blue;
7 │ }
8 │
9 ━ b {
10 ━ color: red;
11 ━ }
12 │
13 │ b1 {
14 │ color: blue;
15 │ }
16 │
17 ━ c {
18 ━ color: red;
19 ━ }`.trim(),
▌ 1 │ a {
▌ 2 │ color: red;
▌ 3 │ }
4 │
5 │ a1 {
6 │ color: blue;

6 │ color: blue;
7 │ }
8 │
▌ 9 │ b {
▌ 10 │ color: red;
▌ 11 │ }
12 │
13 │ b1 {
14 │ color: blue;
15 │ }
16 │
▌ 17 │ c {
▌ 18 │ color: red;
▌ 19 │ }`.trim(),
)
})
})
Expand Down
67 changes: 59 additions & 8 deletions src/cli/reporters/pretty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,24 @@ function indent(line?: string): string {
return (line || '').replace(/^\t+/, (tabs) => ' '.repeat(tabs.length * 4))
}

let line_number = (num: number, covered: boolean = true) => `${num.toString().padStart(5, ' ')} ${covered ? '│' : '━'} `
let line_number = (num: number) => `${num.toString().padStart(5, ' ')} `

function percentage(ratio: number, decimals: number = 2): string {
return `${(ratio * 100).toFixed(ratio === 1 ? 0 : decimals)}%`
}

export type TextStyle = 'bold' | 'red' | 'dim' | 'green'
export type TextStyle =
| 'bold'
| 'red'
| 'dim'
| 'green'
| 'magenta'
| 'cyan'
| 'blue'
| 'blueBright'
| 'magentaBright'
| 'cyanBright'
| 'greenBright'

type StyleTextFn = (style: TextStyle | TextStyle[], input: string) => string

Expand All @@ -23,6 +34,46 @@ export type PrintLinesDependencies = {
print_width?: number
}

function highlight(css: string, styleText: StyleTextFn): string {
// atrule
if (css.trim().startsWith('@')) {
let at_pos = css.indexOf('@')
let space_pos = css.indexOf(' ', at_pos)
let name = css.slice(0, space_pos)
let is_empty = css.endsWith('{}')
let prelude = css.slice(space_pos, is_empty ? -2 : -1)
return [styleText('blueBright', name), styleText('magentaBright', prelude), is_empty ? '{}' : '{'].join('')
}

// declaration
if (css.includes(':') && css.endsWith(';')) {
return [styleText('cyanBright', css.slice(0, css.indexOf(':'))), ':', css.slice(css.indexOf(':') + 1, css.length - 1), ';'].join('')
}

// Empty rule
if (css.endsWith('{}')) {
return [styleText('greenBright', css.slice(0, -2)), '{}'].join('')
}

// Closing }
if (css.endsWith('}')) {
return css
}

// empty line
if (css.trim() === '') {
return css
}

// selector,
if (css.endsWith(',')) {
return [styleText('greenBright', css.slice(0, -1)), ','].join('')
}

// selector {
return [styleText('greenBright', css.slice(0, -1)), '{'].join('')
}

export function print_lines({ report, context }: Report, params: CliArguments, { styleText, print_width }: PrintLinesDependencies) {
let output: (string | undefined)[] = []

Expand Down Expand Up @@ -78,7 +129,7 @@ export function print_lines({ report, context }: Report, params: CliArguments, {
) {
output.push()
output.push(styleText('dim', '─'.repeat(print_width)))
output.push(sheet.url)
output.push(`File: ${sheet.url}`)
output.push(`Coverage: ${percentage(sheet.line_coverage_ratio)}, ${sheet.covered_lines}/${sheet.total_lines} lines covered`)

if (min_file_line_coverage && min_file_line_coverage !== 0 && sheet.line_coverage_ratio < min_file_line_coverage) {
Expand All @@ -96,18 +147,18 @@ export function print_lines({ report, context }: Report, params: CliArguments, {
for (let chunk of sheet.chunks.filter((chunk) => !chunk.is_covered)) {
// Render N leading lines
for (let x = Math.max(chunk.start_line - NUM_LEADING_LINES, 1); x < chunk.start_line; x++) {
output.push([styleText('dim', line_number(x)), styleText('dim', indent(lines[x - 1]))].join(''))
output.push([' ', styleText('dim', line_number(x)), styleText('dim', indent(lines[x - 1]))].join(''))
}
// Render the uncovered chunk
for (let i = chunk.start_line; i <= chunk.end_line; i++) {
output.push([styleText('red', line_number(i, false)), indent(lines[i - 1])].join(''))
output.push([styleText('red', '▌'), styleText('dim', line_number(i)), highlight(indent(lines[i - 1]), styleText)].join(''))
}
// Render N trailing lines
for (let y = chunk.end_line + 1; y < Math.min(chunk.end_line + NUM_TRAILING_LINES, lines.length); y++) {
output.push([styleText('dim', line_number(y)), styleText('dim', indent(lines[y - 1]))].join(''))
for (let y = chunk.end_line + 1; y < Math.min(chunk.end_line + NUM_TRAILING_LINES + 1, lines.length); y++) {
output.push([' ', styleText('dim', line_number(y)), styleText('dim', indent(lines[y - 1]))].join(''))
}
// Show empty line between blocks
output.push()
output.push('')
}
}
}
Expand Down
Loading