-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathjsxhint.js
executable file
·146 lines (132 loc) · 4.79 KB
/
jsxhint.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
135
136
137
138
139
140
141
142
143
144
145
146
/**
* JSXHint CLI tool
*
* Copyright 2013 (c) Samuel Reed
* Inspired by and based on JSXHint by Conde Nast
*
* Please see LICENSE for details
*
*/
'use strict';
var fs = require('fs-extra');
var path = require('path');
var Promise = require('bluebird');
var utils = require('./utils');
var debug = require('debug')('jsxhint');
var jstransform = require('jstransform/simple');
try {
var babel = require('babel-core');
} catch(e) {
// ignore
}
/**
* Transform a JSX file into a JS file for linting.
* @async
* @param {String} fileStream Readable stream containing file contents.
* @param {String} fileName Name of the file; "stdin" if reading from stdio.
* @param {Object} opts Options.
* @param {Function} cb The callback to call when it's ready.
*/
function transformJSX(fileStream, fileName, opts, cb){
// Allow omitting filename
if (typeof fileName === "object"){
cb = opts;
opts = fileName;
fileName = fileStream;
}
if (!babel && (opts['--babel'] || opts['--babel-experimental'])) {
throw new Error("Optional babel parser not installed. Please `npm install [-g] babel-core`.");
}
// Allow passing strings into this method e.g. when using it as a lib
if (typeof fileStream === "string"){
fileStream = fs.createReadStream(fileStream, {encoding: "utf8"});
}
return utils.drainStream(fileStream)
.then(function processFile(source) {
var hasExtension = /\.jsx$/.exec(fileName) || fileName === "stdin";
// console.error('has extension', hasExtension);
// console.log(fileName);
if ((opts['--jsx-only'] && hasExtension) || !opts['--jsx-only']) {
try {
return transformSource(source, opts);
} catch(e) {
// Seems that esprima has some problems with some js syntax.
if (opts['--transform-errors'] === 'always' ||
(opts['--transform-errors'] !== 'never' && hasExtension)) {
console.error("Error while transforming file " + fileName + "\n", e.stack);
throw utils.transformError(fileName, e, opts);
}
}
}
return source;
})
.nodeify(cb);
}
function transformSource(source, opts){
if (opts['--babel'] || opts['--babel-experimental']) {
return babel.transform(source, {stage: opts['--babel-experimental'] ? 0 : 2, retainLines: true}).code;
} else {
return jstransform.transform(source, {
react: true,
harmony: opts['--harmony'],
stripTypes: true,
nonStrictEs6module: opts['--non-strict-es6module'] || false,
es6module: opts['--es6module'] || false
}).code;
}
}
/**
* Transform a list of files from jsx. Calls back with a map relating
* the new files (temp files) to the old file names, e.g.
* {tempFile: originalFileName}
*
* @param {Array} files File paths to transform.
* @param {Object} jsxhintOpts Options for JSXHint.
* @param {Object} jshintOpts Options for JSHint.
* @param {Function} cb Callback.
*/
function transformFiles(files, jsxhintOpts, jshintOpts, cb){
return Promise.map(files, function(fileName) {
return transformJSX(fileName, jsxhintOpts);
})
.then(function(filesContents) {
debug("Successfully transformed %d files to JSX.", files.length);
var tempFileNames = utils.createTempFiles(files, filesContents);
debug("Moved %d files to temp directory at %s.", files.length, exports.tmpdir);
// Create map of temp file names to original file names
var fileNameMap = {};
files.forEach(function(fileName, index){
fileNameMap[tempFileNames[index]] = fileName;
});
return fileNameMap;
})
.nodeify(cb);
}
/**
* Given a stream (stdin), transform and save to a temporary file so it can be piped
* into JSHint.
* JSHint in stream mode attempts to read from process.stdin.
* Since we can't reload process.stdin with the new transformed data (without forking),
* we instead just write to a temp file and load it into JSHint.
*
* @param {ReadableStream} fileStream Readable stream containing data to transform.
* @param {Object} jsxhintOpts Options for JSXHint.
* @param {Object} jshintOpts Options for JSHint.
* @param {Function} cb Callback.
*/
function transformStream(fileStream, jsxhintOpts, jshintOpts, cb){
// JSHint now supports a '--filename' option for stdin, allowing overrides to work properly.
var fileName = jshintOpts && jshintOpts.filename.replace(process.cwd(), '') || 'stdin';
return transformJSX(fileStream, fileName, jsxhintOpts)
.then(function(contents){
var tempFileName = utils.createTempFile(path.join(process.cwd(), fileName), contents);
var out = {};
out[tempFileName] = fileName;
return out;
})
.nodeify(cb);
}
exports.tmpdir = utils.tmpdir;
exports.transformJSX = transformJSX;
exports.transformFiles = transformFiles;
exports.transformStream = transformStream;