This repository has been archived by the owner on Feb 23, 2021. It is now read-only.
/
lint-stream.js
134 lines (108 loc) · 3.78 KB
/
lint-stream.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
'use strict';
var spawn = require('child_process').spawn;
var JSONStream = require('jsonstream2');
var path = require('path');
var es = require('event-stream');
var which = require('npm-which');
var commondir = require('commondir');
var through2 = require('through2');
var setRules = require('./set-rules');
var makeFileStream = require('./error-to-file-transform');
var clusterFileMessages = require('./group-file-messages-transform');
var severityTransform = require('./severity-transform');
var process = require('process');
var makeDedupeTransform = require('./dedupe-transform');
function makeArgs(type, files, readFromStdin) {
var args = [
'--config',
path.resolve(__dirname, 'rc', '.' + type + 'rc'),
(type === 'eslint') ? '--format' : '--reporter',
path.resolve(__dirname, 'reporters', type + '.js')
];
if (readFromStdin) {
args.push(type === 'eslint' ? '--stdin' : '-');
} else {
args = args.concat(files);
}
return args;
}
function makeErrorEmitter(type, lintErrorStream) {
return function emitError(error) {
error.linter = type;
lintErrorStream.emit('error', error);
};
}
function getBinPath(type, callback) {
which(type, {cwd: __dirname}, callback);
}
function makeRelativePathFn(dir) {
return function makeRelativePath(file) {
return (dir === file) ?
path.relative(path.dirname(dir), file) :
path.relative(dir, file);
};
}
function makeRelativePathTransform(makeRelativePath) {
return through2.obj(function transform(message, enc, callback) {
// If commondir and message.file are the same, we are linting a
// single file. This makes sure that the file name is printed in
// that case.
message.file = makeRelativePath(message.file);
this.push(message);
callback();
});
}
function execLinter(type, dir, files, opts) {
var makeRelativePath = makeRelativePathFn(dir);
var lintMessages = makeRelativePathTransform(makeRelativePath);
setRules(dir, files, opts.lineLength, setIndentRuleCallback);
function setIndentRuleCallback(err) {
if (err) {
return lintMessages.emit('error', err);
}
getBinPath(type, getBinPathCallback);
}
function getBinPathCallback(err, binPath) {
if (err) {
return lintMessages.emit('error', err);
}
var args = makeArgs(type, files, opts.stdin);
var onError = makeErrorEmitter(type, lintMessages);
var lintProcess = spawn(binPath, args);
if (opts.stdin) {
process.stdin.pipe(lintProcess.stdin);
process.stdin.once('end', function onStdinEnd() {
lintProcess.stdin.end();
});
}
lintProcess.stdout
.pipe(JSONStream.parse('*'))
.pipe(severityTransform())
.pipe(lintMessages)
.on('error', onError);
lintProcess.stderr.on('data', onError);
}
return lintMessages;
}
function lintStream(type, files, opts) {
var dir = commondir(files);
var fileStream = makeFileStream(type, files.map(makeRelativePathFn(dir)));
execLinter(type, dir, files, opts).pipe(fileStream);
return fileStream;
}
function lintTrapStream(linters) {
linters = linters || ['jscs', 'jshint', 'eslint'];
return function lint(files, opts) {
files.sort();
var streams = linters.map(function initLinter(linterName) {
return lintStream(linterName, files, opts);
});
var mergedLintStream = es.merge.apply(es, streams);
var finalStream = makeDedupeTransform();
mergedLintStream
.pipe(clusterFileMessages(linters))
.pipe(finalStream);
return finalStream;
};
}
module.exports = lintTrapStream;