Skip to content

Commit 49d8bde

Browse files
authored
Merge pull request #31 from Realytics/feature/diagnostic-formatter
Add diagnostics/lints formatters
2 parents af91b09 + b175adb commit 49d8bde

File tree

9 files changed

+253
-13
lines changed

9 files changed

+253
-13
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## v0.2.6
2+
* Add diagnostics/lints formatters - `formatter` and `formatterOptions` option
3+
14
## v0.2.5
25
* Add `async` option - more information in `README.md`
36

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ If `false`, disables built-in colors in logger messages. Default: `true`.
8282
* **logger** `object`:
8383
Logger instance. It should be object that implements method: `error`, `warn`, `info`. Default: `console`.
8484

85+
* **formatter** `'default' | 'codeframe' | Function`:
86+
Formatter for diagnostics and lints. By default uses `default` formatter. You can also pass your own formatter as a function
87+
(see `lib/NormalizedMessage.js` and `lib/formatter/` for api reference).
88+
89+
* **formatterOptions** `object`:
90+
Options passed to formatters (currently only `codeframe` - see [available options](https://www.npmjs.com/package/babel-code-frame#options))
91+
8592
* **silent** `boolean`:
8693
If `true`, logger will not be used. Default: `false`.
8794

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
var os = require('os');
2+
var codeFrame = require('babel-code-frame');
3+
var chalk = require('chalk');
4+
var fs = require('fs');
5+
6+
/**
7+
* Create new code frame formatter.
8+
*
9+
* @param options Options for babel-code-frame - see https://www.npmjs.com/package/babel-code-frame
10+
* @returns {codeframeFormatter}
11+
*/
12+
module.exports = function createCodeframeFormatter(options) {
13+
return function codeframeFormatter(message, useColors) {
14+
var colors = new chalk.constructor({enabled: useColors});
15+
var messageColor = message.isWarningSeverity() ? colors.bold.yellow : colors.bold.red;
16+
var positionColor = colors.dim;
17+
18+
var source = message.getFile() && fs.existsSync(message.getFile()) && fs.readFileSync(message.getFile(), 'utf-8');
19+
var frame = '';
20+
21+
if (source) {
22+
frame = codeFrame(
23+
source,
24+
message.line,
25+
message.character,
26+
Object.assign({}, options || {}, { highlightCode: useColors })
27+
)
28+
.split('\n')
29+
.map(function (str) { return ' ' + str; })
30+
.join(os.EOL);
31+
}
32+
33+
return (
34+
messageColor(message.getSeverity().toUpperCase() + ' at ' + message.getFile()) + os.EOL +
35+
positionColor(message.getLine() + ':' + message.getCharacter()) + ' ' + message.getContent() +
36+
(frame ? os.EOL + frame : '')
37+
);
38+
};
39+
};

lib/formatter/defaultFormatter.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
var chalk = require('chalk');
3+
var os = require('os');
4+
5+
/**
6+
* Creates new default formatter.
7+
*
8+
* @returns {defaultFormatter}
9+
*/
10+
module.exports = function createDefaultFormatter() {
11+
return function defaultFormatter(message, useColors) {
12+
var colors = new chalk.constructor({enabled: useColors});
13+
var messageColor = message.isWarningSeverity() ? colors.bold.yellow : colors.bold.red;
14+
var numberColor = colors.bold.cyan;
15+
var codeColor = colors.grey;
16+
17+
return [
18+
messageColor(message.getSeverity().toUpperCase() + ' at ' + message.getFile()) +
19+
'(' + numberColor(message.getLine()) + ',' + numberColor(message.getCharacter()) + '): ',
20+
codeColor(message.getFormattedCode() + ': ') + message.getContent()
21+
].join(os.EOL);
22+
};
23+
};

lib/index.js

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ var chalk = require('chalk');
55
var fs = require('fs');
66
var os = require('os');
77
var isString = require('lodash.isstring');
8+
var isFunction = require('lodash.isfunction');
89
var CancellationToken = require('./CancellationToken');
910
var NormalizedMessage = require('./NormalizedMessage');
11+
var createDefaultFormatter = require('./formatter/defaultFormatter');
12+
var createCodeframeFormatter = require('./formatter/codeframeFormatter');
1013

1114
/**
1215
* ForkTsCheckerWebpackPlugin
@@ -30,7 +33,10 @@ function ForkTsCheckerWebpackPlugin (options) {
3033
this.async = options.async !== false; // default true
3134
this.workersNumber = options.workers || ForkTsCheckerWebpackPlugin.ONE_CPU;
3235
this.memoryLimit = options.memoryLimit || ForkTsCheckerWebpackPlugin.DEFAULT_MEMORY_LIMIT;
33-
this.colors = new chalk.constructor({ enabled: options.colors === undefined ? true : !!options.colors });
36+
this.useColors = options.colors !== false; // default true
37+
this.colors = new chalk.constructor({ enabled: this.useColors });
38+
this.formatter = (options.formatter && isFunction(options.formatter)) ?
39+
options.formatter : ForkTsCheckerWebpackPlugin.createFormatter(options.formatter || 'default', options.formatterOptions || {});
3440

3541
this.tsconfigPath = undefined;
3642
this.tslintPath = undefined;
@@ -62,6 +68,17 @@ ForkTsCheckerWebpackPlugin.ALL_CPUS = os.cpus().length;
6268
ForkTsCheckerWebpackPlugin.ONE_CPU_FREE = Math.max(1, ForkTsCheckerWebpackPlugin.ALL_CPUS - 1);
6369
ForkTsCheckerWebpackPlugin.TWO_CPUS_FREE = Math.max(1, ForkTsCheckerWebpackPlugin.ALL_CPUS - 2);
6470

71+
ForkTsCheckerWebpackPlugin.createFormatter = function (type, options) {
72+
switch (type) {
73+
case 'default':
74+
return createDefaultFormatter(options);
75+
case 'codeframe':
76+
return createCodeframeFormatter(options);
77+
default:
78+
throw new Error('Unknown "' + type + '" formatter. Available are: default, codeframe.');
79+
}
80+
};
81+
6582
ForkTsCheckerWebpackPlugin.prototype.apply = function (compiler) {
6683
this.compiler = compiler;
6784

@@ -384,17 +401,9 @@ ForkTsCheckerWebpackPlugin.prototype.createDoneCallback = function () {
384401
if (!this.silent && this.logger) {
385402
if (this.diagnostics.length || this.lints.length) {
386403
(this.lints || []).concat(this.diagnostics).forEach(function (message) {
387-
var logColor = message.isWarningSeverity() ? this.colors.bold.yellow : this.colors.bold.red;
388-
var logMethod = message.isWarningSeverity() ? this.logger.warn : this.logger.error;
389-
390-
logMethod(
391-
logColor(message.getSeverity().toUpperCase() + ' at ' + message.getFile()) +
392-
'(' + this.colors.bold.cyan(message.getLine()) + ',' + this.colors.bold.cyan(message.getCharacter()) + '): '
393-
);
394-
logMethod(
395-
this.colors.grey(message.getFormattedCode() + ': ') +
396-
message.getContent() + '\n'
397-
);
404+
var formattedMessage = this.formatter(message, this.useColors);
405+
406+
message.isWarningSeverity() ? this.logger.warn(formattedMessage) : this.logger.error(formattedMessage);
398407
}.bind(this));
399408
}
400409
if (!this.diagnostics.length) {

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fork-ts-checker-webpack-plugin",
3-
"version": "0.2.5",
3+
"version": "0.2.6",
44
"description": "Runs typescript type checker and linter on separate process.",
55
"main": "lib/index.js",
66
"files": [
@@ -58,9 +58,11 @@
5858
"webpack": "^2.0.0 || ^3.0.0"
5959
},
6060
"dependencies": {
61+
"babel-code-frame": "^6.22.0",
6162
"chalk": "^1.1.3",
6263
"chokidar": "^1.7.0",
6364
"lodash.endswith": "^4.2.1",
65+
"lodash.isfunction": "^3.0.8",
6466
"lodash.isstring": "^4.0.1",
6567
"lodash.startswith": "^4.2.1"
6668
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
2+
var describe = require('mocha').describe;
3+
var it = require('mocha').it;
4+
var os = require('os');
5+
var beforeEach = require('mocha').beforeEach;
6+
var afterEach = require('mocha').afterEach;
7+
var expect = require('chai').expect;
8+
var mockFs = require('mock-fs');
9+
var NormalizedMessage = require('../../lib/NormalizedMessage');
10+
var createCodeframeFormatter = require('../../lib/formatter/codeframeFormatter');
11+
12+
describe('[UNIT] formatter/codeframeFormatter', function () {
13+
14+
beforeEach(function () {
15+
mockFs({
16+
some: {
17+
'file.ts': [
18+
'class SomeClass {',
19+
' private someProperty: boolean;',
20+
' constructor() {',
21+
' console.log(\'anything special\');',
22+
' }',
23+
'}'
24+
].join('\n')
25+
}
26+
});
27+
});
28+
29+
afterEach(function () {
30+
mockFs.restore();
31+
});
32+
33+
it('should format normalized diagnostic message', function () {
34+
var message = new NormalizedMessage({
35+
type: NormalizedMessage.TYPE_DIAGNOSTIC,
36+
code: 123,
37+
severity: NormalizedMessage.SEVERITY_ERROR,
38+
content: 'Some diagnostic content',
39+
file: 'some/file.ts',
40+
line: 1,
41+
character: 7
42+
});
43+
var formatter = createCodeframeFormatter({
44+
linesAbove: 1,
45+
linesBelow: 1
46+
});
47+
var formattedMessage = formatter(message, false);
48+
49+
expect(formattedMessage).to.be.equal(
50+
'ERROR at some/file.ts' + os.EOL +
51+
'1:7 Some diagnostic content' + os.EOL +
52+
' > 1 | class SomeClass {' + os.EOL +
53+
' | ^' + os.EOL +
54+
' 2 | private someProperty: boolean;'
55+
);
56+
});
57+
58+
it('should format normalized lint message', function () {
59+
var message = new NormalizedMessage({
60+
type: NormalizedMessage.TYPE_LINT,
61+
code: 'some-lint-rule',
62+
severity: NormalizedMessage.SEVERITY_WARNING,
63+
content: 'Some lint content',
64+
file: 'some/file.ts',
65+
line: 2,
66+
character: 11
67+
});
68+
var formatter = createCodeframeFormatter({
69+
linesAbove: 1,
70+
linesBelow: 1
71+
});
72+
var formattedMessage = formatter(message, false);
73+
74+
expect(formattedMessage).to.be.equal(
75+
'WARNING at some/file.ts' + os.EOL +
76+
'2:11 Some lint content' + os.EOL +
77+
' 1 | class SomeClass {' + os.EOL +
78+
' > 2 | private someProperty: boolean;' + os.EOL +
79+
' | ^' + os.EOL +
80+
' 3 | constructor() {'
81+
);
82+
});
83+
84+
it('should format normalized message without file', function () {
85+
var message = new NormalizedMessage({
86+
type: NormalizedMessage.TYPE_LINT,
87+
code: 'some-lint-rule',
88+
severity: NormalizedMessage.SEVERITY_WARNING,
89+
content: 'Some lint content',
90+
file: 'some/unknown-file.ts',
91+
line: 2,
92+
character: 11
93+
});
94+
var formatter = createCodeframeFormatter({
95+
linesAbove: 1,
96+
linesBelow: 1
97+
});
98+
var formattedMessage = formatter(message, false);
99+
100+
expect(formattedMessage).to.be.equal(
101+
'WARNING at some/unknown-file.ts' + os.EOL +
102+
'2:11 Some lint content'
103+
);
104+
});
105+
});

test/unit/defaultFormatter.spec.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
var describe = require('mocha').describe;
3+
var it = require('mocha').it;
4+
var os = require('os');
5+
var expect = require('chai').expect;
6+
var NormalizedMessage = require('../../lib/NormalizedMessage');
7+
var createDefaultFormatter = require('../../lib/formatter/defaultFormatter');
8+
9+
describe('[UNIT] formatter/defaultFormatter', function () {
10+
11+
it('should format normalized diagnostic message', function () {
12+
var message = new NormalizedMessage({
13+
type: NormalizedMessage.TYPE_DIAGNOSTIC,
14+
code: 123,
15+
severity: NormalizedMessage.SEVERITY_ERROR,
16+
content: 'Some diagnostic content',
17+
file: '/some/file.ts',
18+
line: 1,
19+
character: 5
20+
});
21+
var formatter = createDefaultFormatter();
22+
var formattedMessage = formatter(message, false);
23+
24+
expect(formattedMessage).to.be.equal(
25+
'ERROR at /some/file.ts(1,5): ' + os.EOL +
26+
'TS123: Some diagnostic content'
27+
);
28+
});
29+
30+
it('should format normalized lint message', function () {
31+
var message = new NormalizedMessage({
32+
type: NormalizedMessage.TYPE_LINT,
33+
code: 'some-lint-rule',
34+
severity: NormalizedMessage.SEVERITY_WARNING,
35+
content: 'Some lint content',
36+
file: '/some/file.ts',
37+
line: 2,
38+
character: 6
39+
});
40+
var formatter = createDefaultFormatter();
41+
var formattedMessage = formatter(message, false);
42+
43+
expect(formattedMessage).to.be.equal(
44+
'WARNING at /some/file.ts(2,6): ' + os.EOL +
45+
'some-lint-rule: Some lint content'
46+
);
47+
});
48+
});

yarn.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,6 +1548,10 @@ lodash.isarray@^3.0.0:
15481548
version "3.0.4"
15491549
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
15501550

1551+
lodash.isfunction@^3.0.8:
1552+
version "3.0.8"
1553+
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz#4db709fc81bc4a8fd7127a458a5346c5cdce2c6b"
1554+
15511555
lodash.isstring@^4.0.1:
15521556
version "4.0.1"
15531557
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"

0 commit comments

Comments
 (0)