Skip to content

Commit

Permalink
Merge pull request #31 from Realytics/feature/diagnostic-formatter
Browse files Browse the repository at this point in the history
Add diagnostics/lints formatters
  • Loading branch information
piotr-oles committed Jul 8, 2017
2 parents af91b09 + b175adb commit 49d8bde
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v0.2.6
* Add diagnostics/lints formatters - `formatter` and `formatterOptions` option

## v0.2.5
* Add `async` option - more information in `README.md`

Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ If `false`, disables built-in colors in logger messages. Default: `true`.
* **logger** `object`:
Logger instance. It should be object that implements method: `error`, `warn`, `info`. Default: `console`.

* **formatter** `'default' | 'codeframe' | Function`:
Formatter for diagnostics and lints. By default uses `default` formatter. You can also pass your own formatter as a function
(see `lib/NormalizedMessage.js` and `lib/formatter/` for api reference).

* **formatterOptions** `object`:
Options passed to formatters (currently only `codeframe` - see [available options](https://www.npmjs.com/package/babel-code-frame#options))

* **silent** `boolean`:
If `true`, logger will not be used. Default: `false`.

Expand Down
39 changes: 39 additions & 0 deletions lib/formatter/codeframeFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
var os = require('os');
var codeFrame = require('babel-code-frame');
var chalk = require('chalk');
var fs = require('fs');

/**
* Create new code frame formatter.
*
* @param options Options for babel-code-frame - see https://www.npmjs.com/package/babel-code-frame
* @returns {codeframeFormatter}
*/
module.exports = function createCodeframeFormatter(options) {
return function codeframeFormatter(message, useColors) {
var colors = new chalk.constructor({enabled: useColors});
var messageColor = message.isWarningSeverity() ? colors.bold.yellow : colors.bold.red;
var positionColor = colors.dim;

var source = message.getFile() && fs.existsSync(message.getFile()) && fs.readFileSync(message.getFile(), 'utf-8');
var frame = '';

if (source) {
frame = codeFrame(
source,
message.line,
message.character,
Object.assign({}, options || {}, { highlightCode: useColors })
)
.split('\n')
.map(function (str) { return ' ' + str; })
.join(os.EOL);
}

return (
messageColor(message.getSeverity().toUpperCase() + ' at ' + message.getFile()) + os.EOL +
positionColor(message.getLine() + ':' + message.getCharacter()) + ' ' + message.getContent() +
(frame ? os.EOL + frame : '')
);
};
};
23 changes: 23 additions & 0 deletions lib/formatter/defaultFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

var chalk = require('chalk');
var os = require('os');

/**
* Creates new default formatter.
*
* @returns {defaultFormatter}
*/
module.exports = function createDefaultFormatter() {
return function defaultFormatter(message, useColors) {
var colors = new chalk.constructor({enabled: useColors});
var messageColor = message.isWarningSeverity() ? colors.bold.yellow : colors.bold.red;
var numberColor = colors.bold.cyan;
var codeColor = colors.grey;

return [
messageColor(message.getSeverity().toUpperCase() + ' at ' + message.getFile()) +
'(' + numberColor(message.getLine()) + ',' + numberColor(message.getCharacter()) + '): ',
codeColor(message.getFormattedCode() + ': ') + message.getContent()
].join(os.EOL);
};
};
33 changes: 21 additions & 12 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ var chalk = require('chalk');
var fs = require('fs');
var os = require('os');
var isString = require('lodash.isstring');
var isFunction = require('lodash.isfunction');
var CancellationToken = require('./CancellationToken');
var NormalizedMessage = require('./NormalizedMessage');
var createDefaultFormatter = require('./formatter/defaultFormatter');
var createCodeframeFormatter = require('./formatter/codeframeFormatter');

/**
* ForkTsCheckerWebpackPlugin
Expand All @@ -30,7 +33,10 @@ function ForkTsCheckerWebpackPlugin (options) {
this.async = options.async !== false; // default true
this.workersNumber = options.workers || ForkTsCheckerWebpackPlugin.ONE_CPU;
this.memoryLimit = options.memoryLimit || ForkTsCheckerWebpackPlugin.DEFAULT_MEMORY_LIMIT;
this.colors = new chalk.constructor({ enabled: options.colors === undefined ? true : !!options.colors });
this.useColors = options.colors !== false; // default true
this.colors = new chalk.constructor({ enabled: this.useColors });
this.formatter = (options.formatter && isFunction(options.formatter)) ?
options.formatter : ForkTsCheckerWebpackPlugin.createFormatter(options.formatter || 'default', options.formatterOptions || {});

this.tsconfigPath = undefined;
this.tslintPath = undefined;
Expand Down Expand Up @@ -62,6 +68,17 @@ ForkTsCheckerWebpackPlugin.ALL_CPUS = os.cpus().length;
ForkTsCheckerWebpackPlugin.ONE_CPU_FREE = Math.max(1, ForkTsCheckerWebpackPlugin.ALL_CPUS - 1);
ForkTsCheckerWebpackPlugin.TWO_CPUS_FREE = Math.max(1, ForkTsCheckerWebpackPlugin.ALL_CPUS - 2);

ForkTsCheckerWebpackPlugin.createFormatter = function (type, options) {
switch (type) {
case 'default':
return createDefaultFormatter(options);
case 'codeframe':
return createCodeframeFormatter(options);
default:
throw new Error('Unknown "' + type + '" formatter. Available are: default, codeframe.');
}
};

ForkTsCheckerWebpackPlugin.prototype.apply = function (compiler) {
this.compiler = compiler;

Expand Down Expand Up @@ -384,17 +401,9 @@ ForkTsCheckerWebpackPlugin.prototype.createDoneCallback = function () {
if (!this.silent && this.logger) {
if (this.diagnostics.length || this.lints.length) {
(this.lints || []).concat(this.diagnostics).forEach(function (message) {
var logColor = message.isWarningSeverity() ? this.colors.bold.yellow : this.colors.bold.red;
var logMethod = message.isWarningSeverity() ? this.logger.warn : this.logger.error;

logMethod(
logColor(message.getSeverity().toUpperCase() + ' at ' + message.getFile()) +
'(' + this.colors.bold.cyan(message.getLine()) + ',' + this.colors.bold.cyan(message.getCharacter()) + '): '
);
logMethod(
this.colors.grey(message.getFormattedCode() + ': ') +
message.getContent() + '\n'
);
var formattedMessage = this.formatter(message, this.useColors);

message.isWarningSeverity() ? this.logger.warn(formattedMessage) : this.logger.error(formattedMessage);
}.bind(this));
}
if (!this.diagnostics.length) {
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fork-ts-checker-webpack-plugin",
"version": "0.2.5",
"version": "0.2.6",
"description": "Runs typescript type checker and linter on separate process.",
"main": "lib/index.js",
"files": [
Expand Down Expand Up @@ -58,9 +58,11 @@
"webpack": "^2.0.0 || ^3.0.0"
},
"dependencies": {
"babel-code-frame": "^6.22.0",
"chalk": "^1.1.3",
"chokidar": "^1.7.0",
"lodash.endswith": "^4.2.1",
"lodash.isfunction": "^3.0.8",
"lodash.isstring": "^4.0.1",
"lodash.startswith": "^4.2.1"
}
Expand Down
105 changes: 105 additions & 0 deletions test/unit/codeframeFormatter.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@

var describe = require('mocha').describe;
var it = require('mocha').it;
var os = require('os');
var beforeEach = require('mocha').beforeEach;
var afterEach = require('mocha').afterEach;
var expect = require('chai').expect;
var mockFs = require('mock-fs');
var NormalizedMessage = require('../../lib/NormalizedMessage');
var createCodeframeFormatter = require('../../lib/formatter/codeframeFormatter');

describe('[UNIT] formatter/codeframeFormatter', function () {

beforeEach(function () {
mockFs({
some: {
'file.ts': [
'class SomeClass {',
' private someProperty: boolean;',
' constructor() {',
' console.log(\'anything special\');',
' }',
'}'
].join('\n')
}
});
});

afterEach(function () {
mockFs.restore();
});

it('should format normalized diagnostic message', function () {
var message = new NormalizedMessage({
type: NormalizedMessage.TYPE_DIAGNOSTIC,
code: 123,
severity: NormalizedMessage.SEVERITY_ERROR,
content: 'Some diagnostic content',
file: 'some/file.ts',
line: 1,
character: 7
});
var formatter = createCodeframeFormatter({
linesAbove: 1,
linesBelow: 1
});
var formattedMessage = formatter(message, false);

expect(formattedMessage).to.be.equal(
'ERROR at some/file.ts' + os.EOL +
'1:7 Some diagnostic content' + os.EOL +
' > 1 | class SomeClass {' + os.EOL +
' | ^' + os.EOL +
' 2 | private someProperty: boolean;'
);
});

it('should format normalized lint message', function () {
var message = new NormalizedMessage({
type: NormalizedMessage.TYPE_LINT,
code: 'some-lint-rule',
severity: NormalizedMessage.SEVERITY_WARNING,
content: 'Some lint content',
file: 'some/file.ts',
line: 2,
character: 11
});
var formatter = createCodeframeFormatter({
linesAbove: 1,
linesBelow: 1
});
var formattedMessage = formatter(message, false);

expect(formattedMessage).to.be.equal(
'WARNING at some/file.ts' + os.EOL +
'2:11 Some lint content' + os.EOL +
' 1 | class SomeClass {' + os.EOL +
' > 2 | private someProperty: boolean;' + os.EOL +
' | ^' + os.EOL +
' 3 | constructor() {'
);
});

it('should format normalized message without file', function () {
var message = new NormalizedMessage({
type: NormalizedMessage.TYPE_LINT,
code: 'some-lint-rule',
severity: NormalizedMessage.SEVERITY_WARNING,
content: 'Some lint content',
file: 'some/unknown-file.ts',
line: 2,
character: 11
});
var formatter = createCodeframeFormatter({
linesAbove: 1,
linesBelow: 1
});
var formattedMessage = formatter(message, false);

expect(formattedMessage).to.be.equal(
'WARNING at some/unknown-file.ts' + os.EOL +
'2:11 Some lint content'
);
});
});
48 changes: 48 additions & 0 deletions test/unit/defaultFormatter.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

var describe = require('mocha').describe;
var it = require('mocha').it;
var os = require('os');
var expect = require('chai').expect;
var NormalizedMessage = require('../../lib/NormalizedMessage');
var createDefaultFormatter = require('../../lib/formatter/defaultFormatter');

describe('[UNIT] formatter/defaultFormatter', function () {

it('should format normalized diagnostic message', function () {
var message = new NormalizedMessage({
type: NormalizedMessage.TYPE_DIAGNOSTIC,
code: 123,
severity: NormalizedMessage.SEVERITY_ERROR,
content: 'Some diagnostic content',
file: '/some/file.ts',
line: 1,
character: 5
});
var formatter = createDefaultFormatter();
var formattedMessage = formatter(message, false);

expect(formattedMessage).to.be.equal(
'ERROR at /some/file.ts(1,5): ' + os.EOL +
'TS123: Some diagnostic content'
);
});

it('should format normalized lint message', function () {
var message = new NormalizedMessage({
type: NormalizedMessage.TYPE_LINT,
code: 'some-lint-rule',
severity: NormalizedMessage.SEVERITY_WARNING,
content: 'Some lint content',
file: '/some/file.ts',
line: 2,
character: 6
});
var formatter = createDefaultFormatter();
var formattedMessage = formatter(message, false);

expect(formattedMessage).to.be.equal(
'WARNING at /some/file.ts(2,6): ' + os.EOL +
'some-lint-rule: Some lint content'
);
});
});
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1548,6 +1548,10 @@ lodash.isarray@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"

lodash.isfunction@^3.0.8:
version "3.0.8"
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz#4db709fc81bc4a8fd7127a458a5346c5cdce2c6b"

lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
Expand Down

0 comments on commit 49d8bde

Please sign in to comment.