This commit is contained in:
darenhsu
2022-07-17 13:16:16 +08:00
parent 84759556ff
commit befd344ab0
28070 changed files with 4008428 additions and 1 deletions
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
class ESLintError extends Error {
constructor(messages) {
super(messages);
this.name = 'ESLintError';
this.stack = false;
}
}
exports.default = ESLintError;
+203
View File
@@ -0,0 +1,203 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _process = _interopRequireDefault(require("process"));
var _path = require("path");
var _fsExtra = require("fs-extra");
var _loaderUtils = require("loader-utils");
var _ESLintError = _interopRequireDefault(require("./ESLintError"));
var _createEngine = _interopRequireDefault(require("./createEngine"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
class Linter {
constructor(loaderContext, options) {
this.loaderContext = loaderContext;
this.options = options;
this.resourcePath = this.parseResourcePath();
const {
CLIEngine,
engine
} = (0, _createEngine.default)(options);
this.CLIEngine = CLIEngine;
this.engine = engine;
}
parseResourcePath() {
const cwd = _process.default.cwd();
let {
resourcePath
} = this.loaderContext; // remove cwd from resource path in case webpack has been started from project
// root, to allow having relative paths in .eslintignore
// istanbul ignore next
if (resourcePath.indexOf(cwd) === 0) {
resourcePath = resourcePath.substr(cwd.length + (cwd === '/' ? 0 : 1));
}
return resourcePath;
}
lint(content) {
try {
return this.engine.executeOnText(content, this.resourcePath, true);
} catch (_) {
this.getEmitter(false)(_);
return {
src: content
};
}
}
printOutput(data) {
const {
options
} = this; // skip ignored file warning
if (this.constructor.skipIgnoredFileWarning(data)) {
return;
} // quiet filter done now
// eslint allow rules to be specified in the input between comments
// so we can found warnings defined in the input itself
const res = this.filter(data); // if enabled, use eslint auto-fixing where possible
if (options.fix) {
this.autoFix(res);
} // skip if no errors or warnings
if (res.errorCount < 1 && res.warningCount < 1) {
return;
}
const results = this.parseResults(res); // Do not analyze if there are no results or eslint config
if (!results) {
return;
}
const messages = options.formatter(results);
this.reportOutput(results, messages);
this.failOnErrorOrWarning(res, messages);
const emitter = this.getEmitter(res);
emitter(new _ESLintError.default(messages));
}
static skipIgnoredFileWarning(res) {
return res && res.warningCount === 1 && res.results && res.results[0] && res.results[0].messages[0] && res.results[0].messages[0].message && res.results[0].messages[0].message.indexOf('ignore') > 1;
}
filter(data) {
const res = data; // quiet filter done now
// eslint allow rules to be specified in the input between comments
// so we can found warnings defined in the input itself
if (this.options.quiet && res && res.warningCount && res.results && res.results[0]) {
res.warningCount = 0;
res.results[0].warningCount = 0;
res.results[0].messages = res.results[0].messages.filter(message => message.severity !== 1);
}
return res;
}
autoFix(res) {
if (res && res.results && res.results[0] && (res.results[0].output !== res.src || res.results[0].fixableErrorCount > 0 || res.results[0].fixableWarningCount > 0)) {
this.CLIEngine.outputFixes(res);
}
}
parseResults({
results
}) {
// add filename for each results so formatter can have relevant filename
if (results) {
results.forEach(r => {
// eslint-disable-next-line no-param-reassign
r.filePath = this.loaderContext.resourcePath;
});
}
return results;
}
reportOutput(results, messages) {
const {
outputReport
} = this.options;
if (!outputReport || !outputReport.filePath) {
return;
}
let content = messages; // if a different formatter is passed in as an option use that
if (outputReport.formatter) {
content = outputReport.formatter(results);
}
let filePath = (0, _loaderUtils.interpolateName)(this.loaderContext, outputReport.filePath, {
content
});
if (!(0, _path.isAbsolute)(filePath)) {
filePath = (0, _path.join)( // eslint-disable-next-line no-underscore-dangle
this.loaderContext._compiler.options.output.path, filePath);
}
(0, _fsExtra.ensureFileSync)(filePath);
(0, _fsExtra.writeFileSync)(filePath, content);
}
failOnErrorOrWarning({
errorCount,
warningCount
}, messages) {
const {
failOnError,
failOnWarning
} = this.options;
if (failOnError && errorCount) {
throw new _ESLintError.default(`Module failed because of a eslint error.\n${messages}`);
}
if (failOnWarning && warningCount) {
throw new _ESLintError.default(`Module failed because of a eslint warning.\n${messages}`);
}
}
getEmitter({
errorCount
}) {
const {
options,
loaderContext
} = this; // default behavior: emit error only if we have errors
let emitter = errorCount ? loaderContext.emitError : loaderContext.emitWarning; // force emitError or emitWarning if user want this
if (options.emitError) {
emitter = loaderContext.emitError;
} else if (options.emitWarning) {
emitter = loaderContext.emitWarning;
}
return emitter;
}
}
exports.default = Linter;
+197
View File
@@ -0,0 +1,197 @@
"use strict";
var _fs = _interopRequireDefault(require("fs"));
var _os = _interopRequireDefault(require("os"));
var _path = require("path");
var _util = require("util");
var _zlib = _interopRequireDefault(require("zlib"));
var _crypto = require("crypto");
var _findCacheDir = _interopRequireDefault(require("find-cache-dir"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Original Filesystem Cache implementation by babel-loader
* Licensed under the MIT License
*
* @see https://github.com/babel/babel-loader/commits/master/src/fs-cache.js
* @see https://github.com/babel/babel-loader/commits/master/src/cache.js
*/
/**
* Filesystem Cache
*
* Given a file and a transform function, cache the result into files
* or retrieve the previously cached files if the given file is already known.
*
* @see https://github.com/babel/babel-loader/issues/34
* @see https://github.com/babel/babel-loader/pull/41
*/
// Lazily instantiated when needed
let defaultCacheDirectory = null;
const readFile = (0, _util.promisify)(_fs.default.readFile);
const writeFile = (0, _util.promisify)(_fs.default.writeFile);
const gunzip = (0, _util.promisify)(_zlib.default.gunzip);
const gzip = (0, _util.promisify)(_zlib.default.gzip);
/**
* Read the contents from the compressed file.
*
* @async
* @params {String} filename
* @params {Boolean} compress
*/
const read = async (filename, compress) => {
const data = await readFile(filename + (compress ? '.gz' : ''));
const content = compress ? await gunzip(data) : data;
return JSON.parse(content.toString());
};
/**
* Write contents into a compressed file.
*
* @async
* @params {String} filename
* @params {Boolean} compress
* @params {String} result
*/
const write = async (filename, compress, result) => {
const content = JSON.stringify(result);
const data = compress ? await gzip(content) : content;
return writeFile(filename + (compress ? '.gz' : ''), data);
};
/**
* Build the filename for the cached file
*
* @params {String} source File source code
* @params {String} identifier
* @params {Object} options Options used
*
* @return {String}
*/
const filename = (source, identifier, options) => {
const hash = (0, _crypto.createHash)('md4');
const contents = JSON.stringify({
source,
options,
identifier
});
hash.update(contents);
return `${hash.digest('hex')}.json`;
};
/**
* Handle the cache
*
* @params {String} directory
* @params {Object} params
*/
const handleCache = async (directory, params) => {
const {
source,
options = {},
transform,
cacheIdentifier,
cacheDirectory,
cacheCompression
} = params;
const file = (0, _path.join)(directory, filename(source, cacheIdentifier, options));
try {
// No errors mean that the file was previously cached
// we just need to return it
return await read(file, cacheCompression); // eslint-disable-next-line no-empty
} catch (err) {}
const fallback = typeof cacheDirectory !== 'string' && directory !== _os.default.tmpdir(); // Make sure the directory exists.
try {
_fs.default.mkdirSync(directory, {
recursive: true
});
} catch (err) {
if (fallback) {
return handleCache(_os.default.tmpdir(), params);
}
throw err;
} // Otherwise just transform the file
// return it to the user asap and write it in cache
const result = await transform(source, options);
try {
await write(file, cacheCompression, result);
} catch (err) {
if (fallback) {
// Fallback to tmpdir if node_modules folder not writable
return handleCache(_os.default.tmpdir(), params);
}
throw err;
}
return result;
};
/**
* Retrieve file from cache, or create a new one for future reads
*
* @async
* @param {Object} params
* @param {String} params.cacheDirectory Directory to store cached files
* @param {String} params.cacheIdentifier Unique identifier to bust cache
* @param {Boolean} params.cacheCompression
* @param {String} params.source Original contents of the file to be cached
* @param {Object} params.options Options to be given to the transform fn
* @param {Function} params.transform Function that will transform the
* original file and whose result will be
* cached
*
* @example
*
* cache({
* cacheDirectory: '.tmp/cache',
* cacheIdentifier: 'babel-loader-cachefile',
* cacheCompression: true,
* source: *source code from file*,
* options: {
* experimental: true,
* runtime: true
* },
* transform: function(source, options) {
* var content = *do what you need with the source*
* return content;
* }
* });
*/
module.exports = async params => {
let directory;
if (typeof params.cacheDirectory === 'string') {
directory = params.cacheDirectory;
} else {
if (defaultCacheDirectory === null) {
defaultCacheDirectory = (0, _findCacheDir.default)({
name: 'eslint-loader'
}) || _os.default.tmpdir();
}
directory = defaultCacheDirectory;
}
return handleCache(directory, params);
};
+50
View File
@@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = cacheLoader;
var _package = require("../package.json");
var _cache = _interopRequireDefault(require("./cache"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function cacheLoader(linter, content, map) {
const {
loaderContext,
options,
CLIEngine
} = linter;
const callback = loaderContext.async();
const cacheIdentifier = JSON.stringify({
'eslint-loader': _package.version,
eslint: CLIEngine.version
});
(0, _cache.default)({
cacheDirectory: options.cache,
cacheIdentifier,
cacheCompression: true,
options,
source: content,
transform() {
return linter.lint(content);
}
}).then(res => {
try {
linter.printOutput({ ...res,
src: content
});
} catch (error) {
return callback(error, content, map);
}
return callback(null, content, map);
}).catch(err => {
// istanbul ignore next
return callback(err);
});
}
+5
View File
@@ -0,0 +1,5 @@
"use strict";
const loader = require('./index');
module.exports = loader.default;
+29
View File
@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createEngine;
var _objectHash = _interopRequireDefault(require("object-hash"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const engines = {};
function createEngine(options) {
const {
CLIEngine
} = require(options.eslintPath);
const hash = (0, _objectHash.default)(options);
if (!engines[hash]) {
engines[hash] = new CLIEngine(options);
}
return {
CLIEngine,
engine: engines[hash]
};
}
+53
View File
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getOptions;
var _loaderUtils = _interopRequireDefault(require("loader-utils"));
var _schemaUtils = _interopRequireDefault(require("schema-utils"));
var _options = _interopRequireDefault(require("./options.json"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function getOptions(loaderContext) {
const options = {
eslintPath: 'eslint',
..._loaderUtils.default.getOptions(loaderContext)
};
(0, _schemaUtils.default)(_options.default, options, {
name: 'ESLint Loader',
baseDataPath: 'options'
});
const {
CLIEngine
} = require(options.eslintPath);
options.formatter = getFormatter(CLIEngine, options.formatter);
if (options.outputReport && options.outputReport.formatter) {
options.outputReport.formatter = getFormatter(CLIEngine, options.outputReport.formatter);
}
return options;
}
function getFormatter(CLIEngine, formatter) {
if (typeof formatter === 'function') {
return formatter;
} // Try to get oficial formatter
if (typeof formatter === 'string') {
try {
return CLIEngine.getFormatter(formatter);
} catch (e) {// ignored
}
}
return CLIEngine.getFormatter('stylish');
}
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = loader;
var _getOptions = _interopRequireDefault(require("./getOptions"));
var _Linter = _interopRequireDefault(require("./Linter"));
var _cacheLoader = _interopRequireDefault(require("./cacheLoader"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function loader(content, map) {
const options = (0, _getOptions.default)(this);
const linter = new _Linter.default(this, options);
this.cacheable(); // return early if cached
if (options.cache) {
(0, _cacheLoader.default)(linter, content, map);
return;
}
linter.printOutput(linter.lint(content));
this.callback(null, content, map);
}
+64
View File
@@ -0,0 +1,64 @@
{
"type": "object",
"additionalProperties": true,
"properties": {
"cache": {
"description": "This option will enable caching of the linting results into a file. This is particularly useful in reducing linting time when doing a full build.",
"anyOf": [{ "type": "boolean" }, { "type": "string" }]
},
"eslintPath": {
"description": "Path to `eslint` instance that will be used for linting. If the `eslintPath` is a folder like a official eslint, or specify a `formatter` option. now you dont have to install `eslint` .",
"type": "string"
},
"formatter": {
"description": "Loader accepts a function that will have one argument: an array of eslint messages (object). The function must return the output as a string.",
"anyOf": [{ "type": "string" }, { "instanceof": "Function" }]
},
"fix": {
"description": "This option will enable ESLint autofix feature",
"type": "boolean"
},
"emitError": {
"description": "Loader will always return errors if this option is set to `true`.",
"type": "boolean"
},
"emitWarning": {
"description": "Loader will always return warnings if option is set to `true`. If you're using hot module replacement, you may wish to enable this in development, or else updates will be skipped when there's an eslint error.",
"type": "boolean"
},
"failOnError": {
"description": "Loader will cause the module build to fail if there are any eslint errors.",
"type": "boolean"
},
"failOnWarning": {
"description": "Loader will cause the module build to fail if there are any eslint warnings.",
"type": "boolean"
},
"quiet": {
"description": "Loader will process and report errors only and ignore warnings if this option is set to true",
"type": "boolean"
},
"outputReport": {
"description": "Write the output of the errors to a file, for example a checkstyle xml file for use for reporting on Jenkins CI",
"anyOf": [
{
"type": "boolean"
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"filePath": {
"description": "The `filePath` is relative to the webpack config: output.path",
"anyOf": [{ "type": "string" }]
},
"formatter": {
"description": "You can pass in a different formatter for the output file, if none is passed in the default/configured formatter will be used",
"anyOf": [{ "type": "string" }, { "instanceof": "Function" }]
}
}
}
]
}
}
}