tools/__tasks__/validate-head/javascript.mjs (81 lines of code) (raw):
import execa from 'execa';
import chalk from 'chalk';
import os from 'node:os';
import getChangedFiles from '../lib/get-changed-files.js';
const getCpuCount = () => os.cpus().length;
/** @type {import('listr2').ListrTask} */
const task = {
title: 'Validate committed JS',
task: (ctx, task) =>
task.newListr(
[
{
title: 'Lint committed JS',
task: () =>
getChangedFiles().then((files) => {
const errors = [];
const jsFiles = files.filter(
(file) =>
(file.endsWith('.js') &&
!file.endsWith('.scala.js')) ||
file.endsWith('.jsx') ||
file.startsWith('git-hooks'),
);
const lint = (proc, batchedFiles) =>
proc.then(() =>
Promise.all(
batchedFiles.map((filePath) =>
execa
.shell(
`git show HEAD:${filePath} | eslint --stdin --stdin-filename ${filePath}`,
)
.catch((e) => {
errors.push(e);
}),
),
),
);
const batch = (arr, batchSize) => {
const batchFold = (xss, x) => {
if (!xss.length) {
return [[x]];
}
if (xss[0].length < batchSize) {
return [
xss[0].concat(x),
...xss.slice(1),
];
}
return [[x], ...xss];
};
return arr.reduce(batchFold, []);
};
return batch(jsFiles, getCpuCount())
.reduce(lint, Promise.resolve())
.then(() => {
if (errors.length) {
const error = errors.reduce(
(acc, curr) => {
acc.stdout += curr.stdout;
return acc;
},
{ stdout: '' },
);
error.stdout += `\n${chalk.red(
`✋ Your changes have not been pushed.\n${chalk.reset(
`You may be able to fix things by running ${chalk.dim(
'make fix-commits',
)}.`,
)}`,
)}`;
return Promise.reject(error);
}
return Promise.resolve();
});
}),
},
],
{ concurrent: !!ctx.verbose ? false : true },
),
};
export default task;