@seadub/clang-format-lint
Version:
Validate and/or fix formatting of files via clang-format
72 lines (63 loc) • 2.19 kB
JavaScript
const clangFormat = require('clang-format');
const pLimit = require('p-limit');
/**
*
* @param {string} filepath
* @param {boolean} fix
* @returns {Promise<undefined|Error>}
*/
function lintFile(filepath, fix) {
return new Promise((resolve, reject) => {
let stdout = '';
const args = [ '-style=file' ];
if (fix) {
args.push('-i');
} else {
args.push('-output-replacements-xml');
}
args.push(filepath);
const proc = clangFormat.spawnClangFormat(args, () => {}, 'pipe');
proc.stdout.on('data', function (data) {
stdout += data.toString();
});
proc.on('close', function (exit) {
if (exit) {
// Should we be rejecting if the exit code is non-zero? It'll stop processing *all* files
return reject(new Error(`Failed to execute clang-format on ${filepath}. Exit code: ${exit}`));
}
if (fix) {
return resolve();
}
// doing validation...
const modified = stdout.replace(/\r?\n/g, '');
if (modified !== '<?xml version=\'1.0\'?><replacements xml:space=\'preserve\' incomplete_format=\'false\'></replacements>') {
// Record failure, because formatting is bad.
// TODO Get the correctly formatted source? Give more details on the bad sections?
// Instead of rejecting, resolve with the error - so we ensure every file gets processed!
resolve(new Error(`Formatting incorrect on "${filepath}", proposed changes: ${stdout}`));
}
resolve();
});
});
}
/**
* @param {string[]} files list of filepaths to validate/fix
* @param {integer} execLimit maximum number of files to process simultaneously
* @param {boolean} [fix=false] automatically fix the files?
* @throws {Error} if any files failed validation
*/
async function main(files, execLimit, fix = false) {
const limit = pLimit(execLimit);
const promises = files.map(file => limit(lintFile, file, fix));
const results = await Promise.all(promises);
// filter results to ones containing Error instances
const errors = results.filter(r => r instanceof Error);
if (errors.length > 0) {
const error = new Error(errors.join('\n'));
error.code = 'ELINTFAILURE';
throw error;
}
}
module.exports = main;
;