Skip to content

Commit

Permalink
Add CSV formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
gburgett committed Oct 28, 2022
1 parent e674200 commit 9e15577
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 19 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"async-toolbox": "^0.4.2",
"chalk": "^2.4.2",
"cheerio": "^1.0.0-rc.3",
"csv-stringify": "^6.2.0",
"cross-fetch": "^3.0.2",
"es6-promise": "^4.2.6",
"jsonpath-plus": "^5.0.2",
Expand Down
92 changes: 92 additions & 0 deletions src/formatters/csv.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@

import { } from 'async-toolbox/stream'
import { Logger } from '../logger'
import { ErrorResult, Result, SuccessResult } from '../model'
import { parseUrl } from '../url'
import { CsvFormatter } from './csv'

// tslint:disable: max-line-length

describe('CsvFormatter', () => {
it('logs the result to the console', async () => {
const messages: string[] = []
const logger = { log: (msg: string) => messages.push(msg) }

const instance = new CsvFormatter({
logger: logger as unknown as Logger,
})
const result: SuccessResult = {
type: 'success',
status: 200,
method: 'GET',
url: parseUrl('http://test.com/#'),
contentType: 'text/html',
host: 'test.com',
ms: 123,
links: [],
headers: {},
}

// act
instance.write(result)
await instance.endAsync()

// assert
expect(messages.length).toEqual(2)
expect(messages[0]).toEqual('status,method,url,contentType,ms,parent,error')
expect(messages[1]).toEqual('200,GET,http://test.com/#,text/html,123,,')
})


it('merges several redirects', async () => {
const messages: string[] = []
const logger = { log: (msg: string) => messages.push(msg) }

const instance = new CsvFormatter({
logger: logger as unknown as Logger,
})
const top: SuccessResult = {
type: 'success',
status: 200,
method: 'GET',
url: parseUrl('http://test.com/#'),
contentType: 'text/html',
host: 'test.com',
ms: 123,
links: [parseUrl('http://test.com/r1')],
headers: {},
}

// tslint:disable: max-line-length
const redirects: SuccessResult[] = [
{ type: 'success', status: 301, ms: 1, url: parseUrl('http://test.com/r1'), parent: top, method: 'GET', contentType: '', host: 'test.com', links: [], headers: {} },
]
redirects.push({ type: 'success', status: 302, ms: 1, url: parseUrl('http://test.com/r2'), parent: redirects[0], method: 'GET', contentType: '', host: 'test.com', links: [], headers: {}})
redirects.push({ type: 'success', status: 307, ms: 1, url: parseUrl('http://test.com/r3'), parent: redirects[1], method: 'GET', contentType: '', host: 'test.com', links: [], headers: {}})
// tslint:disable: max-line-length

const final: SuccessResult = {
type: 'success',
status: 204,
method: 'GET',
url: parseUrl('http://test.com/final'),
parent: redirects[2],
contentType: 'text/html',
host: 'test.com',
ms: 123,
leaf: true,
links: [],
headers: {},
}

// act
instance.write(top)
redirects.forEach((r) => instance.write(r))
instance.write(final)
await instance.endAsync()

// assert
expect(messages.length).toEqual(3)
expect(messages[2]).toEqual('204,GET,http://test.com/r1,text/html,126,http://test.com/#,')
})
})
39 changes: 39 additions & 0 deletions src/formatters/csv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { stringify } from 'csv-stringify/sync';

import { Options } from '../util'
import { TableFormatter, TableFormatterOptions } from './table'

const header = {
status: 'status',
method: 'method',
url: 'url',
contentType: 'contentType',
ms: 'ms',
parent: 'parent',
error: 'error',
}

export class CsvFormatter extends TableFormatter {

constructor(options?: Options<TableFormatterOptions>) {
super({
...options
})
}

protected print(...formattedLine: string[]) {
const { logger } = this.options

const stringifiedLine = stringify([
formattedLine.map((f) => f.trim())
])

if (!this.wroteHeader) {
const formattedHeader = this.columns.map((c) => header[c])
logger.log(stringify([formattedHeader]).trimRight())
this.wroteHeader = true
}

logger.log(stringifiedLine.trimRight())
}
}
36 changes: 21 additions & 15 deletions src/formatters/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ const header = {
}

export class TableFormatter extends Writable {
private readonly options: TableFormatterOptions
private wroteHeader = false
protected readonly options: TableFormatterOptions
protected wroteHeader = false

private readonly columns: Array<keyof typeof header>
protected readonly columns: Array<keyof typeof header>

constructor(options?: Options<TableFormatterOptions>) {
super({
Expand All @@ -50,6 +50,22 @@ export class TableFormatter extends Writable {
cb()
}

protected print(...formattedLine: string[]) {
const { logger, compact } = this.options

if (compact) {
formattedLine = formattedLine.map((col) => col.trim())
} else {
if (!this.wroteHeader) {
const formattedHeader = this.columns.map((c) => header[c])
logger.log(formattedHeader.join('\t'))
this.wroteHeader = true
}
}

logger.log(formattedLine.join('\t'))
}

private _format(result: Result) {
const { logger, verbose, compact, showSkipped } = this.options
if (!showSkipped && isSkippedResult(result)) {
Expand Down Expand Up @@ -78,17 +94,7 @@ export class TableFormatter extends Writable {
error: 'error' in result && result.error.toString(),
}

let formattedLine = this.columns.map((c) => (line[c] || '').padEnd(header[c].length))
if (compact) {
formattedLine = formattedLine.map((col) => col.trim())
} else {
if (!this.wroteHeader) {
const formattedHeader = this.columns.map((c) => header[c])
logger.log(formattedHeader.join('\t'))
this.wroteHeader = true
}
}

logger.log(formattedLine.join('\t'))
const formattedLine = this.columns.map((c) => (line[c] || '').padEnd(header[c].length))
this.print(...formattedLine)
}
}
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { BuildPipeline as BuildPipeline } from './build_pipeline'
import { EventForwarder } from './event_forwarder'
import { FetchInterface, FetchInterfaceWrapper } from './fetch_interface'
import { ConsoleFormatter, ConsoleFormatterOptions } from './formatters/console'
import { CsvFormatter } from './formatters/csv'
import { JsonFormatter, JsonFormatterOptions } from './formatters/json'
import { TableFormatter, TableFormatterOptions } from './formatters/table'
import { WriteOutFormatter, WriteOutFormatterOptions } from './formatters/write-out'
Expand All @@ -22,7 +23,8 @@ const formatters: { [name: string]: (args: FormatterOptions) => Writable<Result>
'table': (args: TableFormatterOptions) => new TableFormatter(args),
'console': (args: ConsoleFormatterOptions) => new ConsoleFormatter(args),
'write-out': (args: WriteOutFormatterOptions) => new WriteOutFormatter(args),
'json': (args: JsonFormatterOptions) => new JsonFormatter(args)
'json': (args: JsonFormatterOptions) => new JsonFormatter(args),
'csv': (args: TableFormatterOptions) => new CsvFormatter(args)
}

type FormatterOptions = TableFormatterOptions & ConsoleFormatterOptions & WriteOutFormatterOptions
Expand Down
7 changes: 4 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ const argv = yargs
})
.option('formatter', {
alias: ['f', 'format'],
description: 'Choose the output formatter or provide a format string',
description: 'Set the output formatter or format string. \n' +
'Options: console (default), table, json, csv, \n' +
'or format string like "url: %{url_effective}"',
type: 'string',
})
.option('skip-leaves', {
Expand All @@ -106,9 +108,8 @@ const argv = yargs
alias: 'i',
array: true,
type: 'string',
description: 'CSS Selector for which HTML elements that should be scanned. ' +
description: 'CSS Selector for which HTML elements to inspect. \n' +
'Examples: "a", "link[rel=\\"canonical\\"]", "img", "script", "form", "iframe", "all"',
defaultDescription: '"a[href]", "link[rel=\\"canonical\\"]'
})
.option('only', {
array: true,
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2600,6 +2600,11 @@ css-what@2.1:
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==

csv-stringify@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-6.2.0.tgz#f89881e8f61293bf5af11f421266b5da7b744030"
integrity sha512-dcUbQLRTTDcgQxgEU8V9IctkaCwHZjZfzUZ5ZB3RY8Y+pXtdtl5iVQHfGzANytFFkRKanYzBXrkfpNdGR7eviA==

d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
Expand Down

0 comments on commit 9e15577

Please sign in to comment.