Skip to content

Commit

Permalink
Add new stylish formatter
Browse files Browse the repository at this point in the history
* Fix how `formatter` is used in `cli.ts`
* Fix #187
  • Loading branch information
sarvaje authored and molant committed May 9, 2017
1 parent 30b441c commit 38c5577
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 10 deletions.
4 changes: 2 additions & 2 deletions .sonarrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"collector": {
"name": "jsdom",
"name": "cdp",
"options": {
"waitFor": 100
}
},
"formatter": "json",
"formatter": "stylish",
"rules": {
"axe": "warning",
"disallowed-headers": "warning",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
"bugs": "https://github.com/MicrosoftEdge/Sonar/issues",
"homepage": "https://github.com/MicrosoftEdge/Sonar#readme",
"dependencies": {
"browserslist": "^2.1.1",
"axe-core": "^2.2.0",
"browserslist": "^2.1.1",
"chalk": "^1.1.3",
"chrome-remote-interface": "^0.22.0",
"debug": "^2.6.1",
Expand Down
9 changes: 4 additions & 5 deletions src/lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,11 @@ export const cli = {
/** Executes the CLI based on an array of arguments that is passed in. */
execute: async (args: string | Array<string> | Object): Promise<number> => {

const format = (results) => {
const format = (formatterName, results) => {
const formatters = resourceLoader.getFormatters();
const formatter = formatters.get(formatterName) || formatters.get('json');

formatters.forEach((formatter) => {
formatter.format(results);
});
formatter.format(results);
};

const currentOptions = options.parse(args);
Expand Down Expand Up @@ -88,7 +87,7 @@ export const cli = {
return result.severity === Severity.error;
});

format(results);
format(engine.formatter, results);

if (hasError) {
exitCode = 1;
Expand Down
66 changes: 66 additions & 0 deletions src/lib/formatters/stylish/stylish.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @fileoverview The basic formatter, it just a table format with diferent colors
* for errors and warnings.
*
* This formatter is based on [eslint stylish formatter](https://github.com/eslint/eslint/blob/master/lib/formatters/stylish.js)
*/

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

import * as chalk from 'chalk';
import * as _ from 'lodash';
import * as table from 'text-table';

import { debug as d } from '../../utils/debug';
import { IFormatter, Severity } from '../../types'; // eslint-disable-line no-unused-vars
import * as logger from '../../utils/logging';

const debug = d(__filename);

const pluralize = (text, count) => {
return `${text}${count !== 1 ? 's' : ''}`;
};

// ------------------------------------------------------------------------------
// Formatter
// ------------------------------------------------------------------------------

const formatter: IFormatter = {
/** Format the problems grouped by `resource` name and sorted by line and column number */
format(messages) {

debug('Formatting results');

const resources = _.groupBy(messages, 'resource');

_.forEach(resources, (msgs, resource) => {
let warnings = 0;
let errors = 0;
const sortedMessages = _.sortBy(msgs, ['line', 'column']);
const tableData = [];

logger.log(chalk.cyan(`${resource}`));
_.forEach(sortedMessages, (msg) => {
const severity = Severity.error === msg.severity ? chalk.red('Error') : chalk.yellow('Warning');

if (Severity.error === msg.severity) {
errors++;
} else {
warnings++;
}
tableData.push([severity, msg.message, msg.ruleId]);
});

logger.log(table(tableData));

const color = errors > 0 ? chalk.red : chalk.yellow;

logger.log(color.bold(`\u2716 Found ${errors} ${pluralize('error', errors)} and ${warnings} ${pluralize('warning', warnings)}`));
logger.log('');
});
}
};

export default formatter;
8 changes: 8 additions & 0 deletions src/lib/sonar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export class Sonar extends EventEmitter {
private messages: Array<IProblem>
private browsersList: Array<String> = [];
private ignoredUrls: Map<string, RegExp[]>;
private _formatter: string

get pageContent() {
return this.collector.html;
Expand All @@ -46,6 +47,10 @@ export class Sonar extends EventEmitter {
return this.browsersList;
}

get formatter() {
return this._formatter;
}

private isIgnored(urls: RegExp[], resource: string) {
if (!urls) {
return false;
Expand All @@ -72,6 +77,9 @@ export class Sonar extends EventEmitter {
this.browsersList = browserslist(config.browserslist);
}

debug('Setting the selected formatter');
this._formatter = config.formatter;

debug('Initializing ignored urls');
this.ignoredUrls = new Map();
if (config.ignoredUrls) {
Expand Down
4 changes: 3 additions & 1 deletion tests/lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ const sonar = {
const formatter = { format: () => { } };
const resourceLoader = {
getFormatters() {
return [formatter];
return new Map([
['json', formatter]
]);
}
};
const logger = {
Expand Down
34 changes: 34 additions & 0 deletions tests/lib/formatters/fixtures/list-of-problems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,43 @@ const multipleproblems: Array<IProblem> = [{
severity: Severity.warning
}];

const multipleproblemsandresources: Array<IProblem> = [{
column: 10,
line: 1,
message: 'This is a problem in line 1 column 10',
resource: 'http://myresource.com/',
ruleId: 'random-rule',
severity: Severity.warning
},
{
column: 1,
line: 10,
message: 'This is a problem in line 10',
resource: 'http://myresource.com/',
ruleId: 'random-rule',
severity: Severity.warning
},
{
column: 1,
line: 5,
message: 'This is a problem in line 5',
resource: 'http://myresource2.com/',
ruleId: 'random-rule',
severity: Severity.error
},
{
column: 1,
line: 1,
message: 'This is a problem in line 1 column 1',
resource: 'http://myresource2.com/',
ruleId: 'random-rule',
severity: Severity.warning
}];

const noproblems: Array<IProblem> = [];

export {
multipleproblems,
multipleproblemsandresources,
noproblems
};
1 change: 0 additions & 1 deletion tests/lib/formatters/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import * as problems from './fixtures/list-of-problems';
import { Severity } from '../../../src/lib/types';

test.beforeEach((t) => {
// const log = sinon.spy(logger, 'log');
sinon.spy(logging, 'log');

t.context.logger = logging;
Expand Down
59 changes: 59 additions & 0 deletions tests/lib/formatters/stylish.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import test from 'ava';
import * as chalk from 'chalk';
import * as sinon from 'sinon';
import * as proxyquire from 'proxyquire';
import * as table from 'text-table';

const logging = { log() { } };

proxyquire('../../../src/lib/formatters/stylish/stylish', { '../../utils/logging': logging });

import stylish from '../../../src/lib/formatters/stylish/stylish';
import * as problems from './fixtures/list-of-problems';

test.beforeEach((t) => {
sinon.spy(logging, 'log');

t.context.logger = logging;
});

test.afterEach((t) => {
t.context.logger.log.restore();
});

test(`Stylish formatter doesn't print anything if no values`, (t) => {
stylish.format(problems.noproblems);

t.is(t.context.logger.log.callCount, 0);
});

test(`Stylish formatter prints a table and a summary for each resource`, (t) => {
stylish.format(problems.multipleproblemsandresources);

const log = t.context.logger.log;
let problem = problems.multipleproblemsandresources[0];
let tableData = [];

tableData.push([chalk.yellow('Warning'), problem.message, problem.ruleId]);
problem = problems.multipleproblemsandresources[1];
tableData.push([chalk.yellow('Warning'), problem.message, problem.ruleId]);

let tableString = table(tableData);

t.is(log.args[0][0], chalk.cyan('http://myresource.com/'));
t.is(log.args[1][0], tableString);
t.is(log.args[2][0], chalk.yellow.bold(`\u2716 Found 0 errors and 2 warnings`));
t.is(log.args[3][0], '');
t.is(log.args[4][0], chalk.cyan('http://myresource2.com/'));

tableData = [];
problem = problems.multipleproblemsandresources[3];
tableData.push([chalk.yellow('Warning'), problem.message, problem.ruleId]);
problem = problems.multipleproblemsandresources[2];
tableData.push([chalk.red('Error'), problem.message, problem.ruleId]);
tableString = table(tableData);

t.is(log.args[5][0], tableString);
t.is(log.args[6][0], chalk.red.bold(`\u2716 Found 1 error and 1 warning`));
t.is(log.args[7][0], '');
});

0 comments on commit 38c5577

Please sign in to comment.