You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
3.1 KiB
160 lines
3.1 KiB
"use strict"; |
|
|
|
const { |
|
cpus |
|
} = require('os'); |
|
|
|
const { |
|
Worker: JestWorker |
|
} = require('jest-worker'); |
|
|
|
const { |
|
getESLintOptions |
|
} = require('./options'); |
|
|
|
const { |
|
jsonStringifyReplacerSortKeys |
|
} = require('./utils'); |
|
/** @type {{[key: string]: any}} */ |
|
|
|
|
|
const cache = {}; |
|
/** @typedef {import('eslint').ESLint} ESLint */ |
|
|
|
/** @typedef {import('eslint').ESLint.LintResult} LintResult */ |
|
|
|
/** @typedef {import('./options').Options} Options */ |
|
|
|
/** @typedef {() => Promise<void>} AsyncTask */ |
|
|
|
/** @typedef {(files: string|string[]) => Promise<LintResult[]>} LintTask */ |
|
|
|
/** @typedef {{threads: number, ESLint: ESLint, eslint: ESLint, lintFiles: LintTask, cleanup: AsyncTask}} Linter */ |
|
|
|
/** @typedef {JestWorker & {lintFiles: LintTask}} Worker */ |
|
|
|
/** |
|
* @param {Options} options |
|
* @returns {Linter} |
|
*/ |
|
|
|
function loadESLint(options) { |
|
const { |
|
eslintPath |
|
} = options; |
|
|
|
const { |
|
ESLint |
|
} = require(eslintPath || 'eslint'); // Filter out loader options before passing the options to ESLint. |
|
|
|
|
|
const eslint = new ESLint(getESLintOptions(options)); |
|
return { |
|
threads: 1, |
|
ESLint, |
|
eslint, |
|
lintFiles: async files => { |
|
const results = await eslint.lintFiles(files); // istanbul ignore else |
|
|
|
if (options.fix) { |
|
await ESLint.outputFixes(results); |
|
} |
|
|
|
return results; |
|
}, |
|
// no-op for non-threaded |
|
cleanup: async () => {} |
|
}; |
|
} |
|
/** |
|
* @param {string|undefined} key |
|
* @param {number} poolSize |
|
* @param {Options} options |
|
* @returns {Linter} |
|
*/ |
|
|
|
|
|
function loadESLintThreaded(key, poolSize, options) { |
|
const cacheKey = getCacheKey(key, options); |
|
const { |
|
eslintPath = 'eslint' |
|
} = options; |
|
|
|
const source = require.resolve('./worker'); |
|
|
|
const workerOptions = { |
|
enableWorkerThreads: true, |
|
numWorkers: poolSize, |
|
setupArgs: [{ |
|
eslintPath, |
|
eslintOptions: getESLintOptions(options) |
|
}] |
|
}; |
|
const local = loadESLint(options); |
|
let worker = |
|
/** @type {Worker?} */ |
|
new JestWorker(source, workerOptions); |
|
/** @type {Linter} */ |
|
|
|
const context = { ...local, |
|
threads: poolSize, |
|
lintFiles: async files => worker && (await worker.lintFiles(files)) || |
|
/* istanbul ignore next */ |
|
[], |
|
cleanup: async () => { |
|
cache[cacheKey] = local; |
|
|
|
context.lintFiles = files => local.lintFiles(files); |
|
|
|
if (worker) { |
|
worker.end(); |
|
worker = null; |
|
} |
|
} |
|
}; |
|
return context; |
|
} |
|
/** |
|
* @param {string|undefined} key |
|
* @param {Options} options |
|
* @returns {Linter} |
|
*/ |
|
|
|
|
|
function getESLint(key, { |
|
threads, |
|
...options |
|
}) { |
|
const max = typeof threads !== 'number' ? threads ? cpus().length - 1 : 1 : |
|
/* istanbul ignore next */ |
|
threads; |
|
const cacheKey = getCacheKey(key, { |
|
threads, |
|
...options |
|
}); |
|
|
|
if (!cache[cacheKey]) { |
|
cache[cacheKey] = max > 1 ? loadESLintThreaded(key, max, options) : loadESLint(options); |
|
} |
|
|
|
return cache[cacheKey]; |
|
} |
|
/** |
|
* @param {string|undefined} key |
|
* @param {Options} options |
|
* @returns {string} |
|
*/ |
|
|
|
|
|
function getCacheKey(key, options) { |
|
return JSON.stringify({ |
|
key, |
|
options |
|
}, jsonStringifyReplacerSortKeys); |
|
} |
|
|
|
module.exports = { |
|
loadESLint, |
|
loadESLintThreaded, |
|
getESLint |
|
}; |