putout
Version:
the pluggable code transformer
154 lines (119 loc) • 3.56 kB
JavaScript
;
const tryCatch = require('try-catch');
const tryToCatch = require('try-to-catch');
const [, eslint] = tryCatch(require, 'eslint');
const {ESLint} = eslint || {};
const {keys} = Object;
const overrideConfigFile = process.env.ESLINT_CONFIG_FILE;
const eslintId = ' (eslint)';
const eslintPluginRegExp = /\/.*\s\(eslint\)$/;
const putoutPluginRegExp = /^putout\/.*\s\(eslint\)$/;
const noConfigFound = (config, configError) => {
if (configError && configError.messageTemplate === 'no-config-found')
return true;
if (configError)
return false;
if (!keys(config.rules).length)
return true;
return false;
};
const cutNewLine = ({message}) => ({
message: message.replace(/\n.*/, ''),
});
const getESLint = ({fix}) => {
const eslint = new ESLint({
fix,
overrideConfig: {
ignorePatterns: [
'!.*',
],
},
...overrideConfigFile && {
overrideConfigFile,
useEslintrc: false,
},
});
return {
calculateConfigForFile: eslint.calculateConfigForFile.bind(eslint),
lintText: eslint.lintText.bind(eslint),
};
};
module.exports = async ({name, code, fix}) => {
const noChanges = [
code,
[],
];
if (!ESLint)
return noChanges;
const [eslintError, eslint] = await tryToCatch(getESLint, {
fix,
});
if (eslintError)
return [
code,
[convertToPlace(cutNewLine(eslintError))],
];
const [configError, config] = await tryToCatch(eslint.calculateConfigForFile, name);
if (noConfigFound(config, configError))
return noChanges;
if (configError) {
return [
code,
[convertToPlace(parseError(configError))],
];
}
disablePutout(config);
// that's right, we disabled "putout" rules in "config"
// and now it is in eslint's cache
const results = await eslint.lintText(code, {
filePath: name,
});
if (!results.length)
return noChanges;
const [report] = results;
const {output} = report;
const places = report.messages.map(convertToPlace);
return [
output || code,
places,
];
};
module.exports._noConfigFound = noConfigFound;
module.exports.eslintPluginRegExp = eslintPluginRegExp;
module.exports.putoutPluginRegExp = putoutPluginRegExp;
const parseRule = (rule) => rule || 'parser';
function convertToPlace({ruleId = 'parser', message, line = 0, column = 0}) {
const rule = `${parseRule(ruleId)}${eslintId}`;
return {
rule,
message,
position: {
line,
column,
},
};
}
function disablePutout(config) {
if (!config.rules['putout/putout'])
return;
config.rules['putout/putout'] = 'off';
}
// when eslint config got errors, table formatter used for reporting
// can't show control characters and crash
//
// https://stackoverflow.com/questions/26741455/how-to-remove-control-characters-from-string
const replaceControlChars = (a) => a.replace(/[\x00-\x1F]/g, '. ');
function parseError(e) {
const {
messageTemplate,
messageData,
message,
} = e;
if (messageTemplate !== 'plugin-missing')
return {
message: replaceControlChars(message),
};
return {
message: `Plugin missing: ${messageData.pluginName}`,
};
}