stylelint-webpack-plugin
Version:
A Stylelint plugin for webpack
120 lines (112 loc) • 3.39 kB
JavaScript
"use strict";
const {
cpus
} = require("node:os");
const {
Worker: JestWorker
} = require("jest-worker");
const {
getStylelintOptions
} = require("./options");
const {
jsonStringifyReplacerSortKeys
} = require("./utils");
const {
getStylelint: getStylelintInstance,
lintFiles,
setup
} = require("./worker");
/** @type {{ [key: string]: Linter }} */
const cache = {};
/** @typedef {{lint: (options: LinterOptions) => Promise<LinterResult>, formatters: { [k: string]: Formatter }}} Stylelint */
/** @typedef {import('stylelint').LintResult} LintResult */
/** @typedef {import('stylelint').LinterOptions} LinterOptions */
/** @typedef {import('stylelint').LinterResult} LinterResult */
/** @typedef {import('stylelint').Formatter} Formatter */
/** @typedef {import('stylelint').FormatterType} FormatterType */
/** @typedef {import('stylelint').RuleMeta} RuleMeta */
/** @typedef {import('./options').Options} Options */
/** @typedef {() => Promise<void>} AsyncTask */
/** @typedef {(files: string|string[]) => Promise<LintResult[]>} LintTask */
/** @typedef {{getStylelint: () => Promise<Stylelint>, lintFiles: LintTask, cleanup: AsyncTask, threads: number }} Linter */
/** @typedef {JestWorker & {lintFiles: LintTask}} Worker */
/**
* @param {Options} options linter options
* @returns {Linter} linter
*/
function loadStylelint(options) {
const stylelintOptions = getStylelintOptions(options);
setup(options, stylelintOptions);
return {
getStylelint: getStylelintInstance,
lintFiles,
cleanup: async () => {},
threads: 1
};
}
/**
* @param {string | undefined} key a cache key
* @param {Options} options options
* @returns {string} a stringified cache key
*/
function getCacheKey(key, options) {
return JSON.stringify({
key,
options
}, jsonStringifyReplacerSortKeys);
}
/**
* @param {string|undefined} key a cache key
* @param {number} poolSize number of workers
* @param {Options} options options
* @returns {Linter} linter
*/
function loadStylelintThreaded(key, poolSize, options) {
const cacheKey = getCacheKey(key, options);
const source = require.resolve("./worker");
const workerOptions = {
enableWorkerThreads: true,
numWorkers: poolSize,
setupArgs: [options, getStylelintOptions(options)]
};
const local = loadStylelint(options);
let worker = /** @type {Worker | null} */
new JestWorker(source, workerOptions);
/** @type {Linter} */
const context = {
...local,
threads: poolSize,
lintFiles: async files => /* istanbul ignore next */
worker ? worker.lintFiles(files) : local.lintFiles(files),
cleanup: async () => {
cache[cacheKey] = local;
context.lintFiles = files => local.lintFiles(files);
/* istanbul ignore next */
if (worker) {
worker.end();
worker = null;
}
}
};
return context;
}
/**
* @param {string|undefined} key a cache key
* @param {Options} options options
* @returns {Linter} linter
*/
function getStylelint(key, {
threads,
...options
}) {
const max = typeof threads !== "number" ? threads ? cpus().length - 1 : 1 : threads;
const cacheKey = getCacheKey(key, {
threads,
...options
});
if (!cache[cacheKey]) {
cache[cacheKey] = max > 1 ? loadStylelintThreaded(key, max, options) : loadStylelint(options);
}
return cache[cacheKey];
}
module.exports = getStylelint;