isml-linter
Version:
ISML Linter is a tool for examining if your project's templates follow a specified set of rules defined by your dev team. The available rules can be roughly grouped into:
330 lines (253 loc) • 11.7 kB
JavaScript
const chalk = require('chalk');
const Constants = require('../Constants');
const ExceptionUtils = require('./ExceptionUtils');
const ConfigUtils = require('./ConfigUtils');
const MAX_LISTED_ERRORS = 30;
const printExceptionMsg = e => {
if (!e.isCustom) {
console.log();
console.log('An error has occurred:');
console.log(e.stack || e);
console.log('If you think this is a bug, please open an issue at:');
console.log(`${Constants.EOL}${Constants.repositoryUrl}${Constants.EOL}${Constants.EOL}`);
}
};
const displayLintingOccurrenceList = lintResult => {
const config = ConfigUtils.load();
const occurrenceLevels = Constants.occurrenceLevels.toArray();
const errorData = getErrorsData(lintResult);
const warningData = getWarningsData(lintResult);
const infoData = getInfoData(lintResult);
const data = {
error : {
messages : errorData.outputMsgList,
qty : errorData.qty
},
warning : {
messages : warningData.outputMsgList,
qty : warningData.qty
},
info : {
messages : infoData.outputMsgList,
qty : infoData.qty
},
total : errorData.qty + warningData.qty + infoData.qty
};
for (let j = 0; j < occurrenceLevels.length; j++) {
const occurrenceGroup = occurrenceLevels[j];
if (data[occurrenceGroup].qty > 0) {
for (let i = 0; i < data[occurrenceGroup].messages.length; i++) {
if (config.printPartialResults && i > MAX_LISTED_ERRORS) {
break;
}
console.log(data[occurrenceGroup].messages[i]);
}
}
}
return data;
};
const displayUnparseableErrors = lintResult => {
const config = ConfigUtils.load();
let partialSum = 0;
if (!config.ignoreUnparseable) {
const INVALID_TEMPLATE = ExceptionUtils.types.INVALID_TEMPLATE;
if (lintResult[INVALID_TEMPLATE] && lintResult[INVALID_TEMPLATE].length > 0) {
console.log(chalk`{red.bold ${Constants.EOL}An Isml abstract syntax tree could not be built for the following templates:}`);
for (let i = 0; i < lintResult[INVALID_TEMPLATE].length; i++) {
if (config.printPartialResults && i > MAX_LISTED_ERRORS) {
break;
}
const error = lintResult[INVALID_TEMPLATE][i];
console.log(chalk.gray(i) + ' ' + error.templatePath + ':' + error.lineNumber);
console.log('\t' + chalk`{red.bold >> }` + `${error.message}${Constants.EOL}`);
partialSum++;
}
}
}
return partialSum;
};
const displayRuleErrors = lintResult => {
const RULE_ERROR = ExceptionUtils.types.RULE_ERROR;
const config = ConfigUtils.load();
let partialSum = 0;
if (lintResult[RULE_ERROR] && lintResult[RULE_ERROR].length > 0) {
console.log(chalk`{red.bold ${Constants.EOL}An unexpected error occurred while applying rules to the following templates:}`);
for (let i = 0; i < lintResult[RULE_ERROR].length; i++) {
if (config.printPartialResults && i > MAX_LISTED_ERRORS) {
break;
}
const error = lintResult[RULE_ERROR][i];
console.log(chalk.gray(i) + '\t' + error.ruleID + ' :\t' + error.templatePath);
partialSum++;
}
}
return partialSum;
};
const displayUnknownErrors = lintResult => {
const UNKNOWN_ERROR = ExceptionUtils.types.UNKNOWN_ERROR;
let partialSum = 0;
if (lintResult[UNKNOWN_ERROR] && lintResult[UNKNOWN_ERROR].length > 0) {
console.log(chalk`{red.bold ${Constants.EOL}An unexpected error happened while parsing the following templates:}`);
const unknownErrorArray = lintResult[UNKNOWN_ERROR];
for (let i = 0; i < unknownErrorArray.length; i++) {
console.log(chalk.gray(i) + '\t' + unknownErrorArray[i]);
partialSum++;
}
console.log(`${Constants.EOL}Please check if your node version is >=10.0.0. If it is, please report the above issues to ${chalk.cyan(Constants.repositoryUrl + '/issues')} and add these files to the ignore list while a fix is not available.`);
}
return partialSum;
};
const getPluralTermString = (singularTerm, qty) => `${qty} ${singularTerm}${qty > 1 ? 's' : ''}`;
const displayOccurrenceList = lintResult => {
displayUnparseableErrors(lintResult);
displayUnknownErrors(lintResult);
displayRuleErrors(lintResult);
// TODO Add this 'config' as a global const;
const config = ConfigUtils.load();
const occurrenceList = displayLintingOccurrenceList(lintResult);
const isThereAnyOccurrence = occurrenceList.error.qty > 0 ||
occurrenceList.warning.qty > 0 ||
occurrenceList.info.qty > 0 ||
lintResult.INVALID_TEMPLATE && lintResult.INVALID_TEMPLATE.length > 0 ||
lintResult.UNKNOWN_ERROR && lintResult.UNKNOWN_ERROR.length > 0;
if (isThereAnyOccurrence) {
console.log(Constants.EOL + '=====================================================');
console.log(Constants.EOL + chalk`{bold Linted ${lintResult.totalTemplatesQty} templates in ${lintResult.elapsedTime} seconds.}`);
if (occurrenceList.error.qty > 0) {
console.log(chalk`{bold ${getPluralTermString('error', occurrenceList.error.qty)} found.}`);
}
if (occurrenceList.warning.qty > 0) {
console.log(chalk`{bold ${getPluralTermString('warning', occurrenceList.warning.qty)} found.}`);
}
if (occurrenceList.info.qty > 0) {
console.log(chalk`{bold ${getPluralTermString('info', occurrenceList.info.qty)} found.}`);
}
if (lintResult.INVALID_TEMPLATE && lintResult.INVALID_TEMPLATE.length > 0) {
console.log(chalk`{bold ${getPluralTermString('template', lintResult.INVALID_TEMPLATE.length)} have an invalid ISML tree.}`);
}
if (lintResult.UNKNOWN_ERROR && lintResult.UNKNOWN_ERROR.length > 0) {
if (lintResult.UNKNOWN_ERROR.length > 1) {
console.log(chalk`{bold There were ${lintResult.UNKNOWN_ERROR.length} unknown errors while parsing templates.}`);
} else {
console.log(chalk`{bold There was 1 unknown error while parsing templates.}`);
}
}
if (config.printPartialResults) {
console.log(chalk`{bold Displaying the first ${MAX_LISTED_ERRORS} occurrences of each group.}` + Constants.EOL);
}
}
};
const displayInvalidTemplatesPaths = templatePathArray => {
console.log(Constants.EOL + chalk`{red.bold Could not find the following templates:}`);
for (let i = 0; i < templatePathArray.length; i++) {
const invalidPath = templatePathArray[i];
console.log(chalk.gray(i) + '\t' + invalidPath);
}
console.log(Constants.EOL);
};
const displayConfigError = () => {
console.log('No configuration found. Please run the following command to create a default configuration file:');
console.log(Constants.EOL + '\t' + chalk.yellow('./node_modules/.bin/isml-linter --init') + Constants.EOL);
};
const displayInvalidCommandError = () => {
console.log('\nInvalid command detected. Please use the following format:');
console.log(Constants.EOL + '\t' + chalk.yellow('./node_modules/.bin/isml-linter [options] [file|dir]*') + Constants.EOL);
console.log('For example:');
console.log(Constants.EOL + '\t' + chalk.yellow('./node_modules/.bin/isml-linter --autofix template1.isml directory1/ directory2/') + Constants.EOL);
};
const displayEslintConfigError = () => {
const config = ConfigUtils.load();
const eslintConfigFileName = config.eslintConfig;
console.log(`The "eslint-to-isscript" rule is enabled, but an ESLint configuration file ${eslintConfigFileName ? '"' + eslintConfigFileName + '" ' : ''}could not be found in the project root directory.'`);
};
const getErrorsData = lintResult => {
const outputMsgList = [];
let qty = 0;
outputMsgList.push(chalk`{red.bold ${Constants.EOL}The following linting errors were found in the templates:}`);
for (const rule in lintResult.errors) {
for (const template in lintResult.errors[rule]) {
outputMsgList.push(Constants.EOL + template);
const occurrenceList = lintResult.errors[rule][template];
for (let i = 0; i < occurrenceList.length; i++) {
const occurrence = occurrenceList[i];
outputMsgList.push(
chalk.gray(occurrence.lineNumber) + '\t' +
chalk.red('error') + '\t' +
occurrence.message
);
qty++;
}
}
}
return {
outputMsgList,
qty
};
};
const getWarningsData = lintResult => {
const outputMsgList = [];
let qty = 0;
outputMsgList.push(chalk`{yellow.bold ${Constants.EOL}The following linting warnings were found in the templates:}`);
for (const rule in lintResult.warnings) {
for (const template in lintResult.warnings[rule]) {
outputMsgList.push(Constants.EOL + template);
const occurrenceList = lintResult.warnings[rule][template];
for (let i = 0; i < occurrenceList.length; i++) {
const occurrence = occurrenceList[i];
outputMsgList.push(
chalk.gray(occurrence.lineNumber) + '\t' +
chalk.yellow('warning') + '\t' +
occurrence.message
);
qty++;
}
}
}
return {
outputMsgList,
qty
};
};
const getInfoData = lintResult => {
const outputMsgList = [];
let qty = 0;
outputMsgList.push(chalk`{cyan.bold ${Constants.EOL}The following linting info items were found in the templates:}`);
for (const rule in lintResult.info) {
for (const template in lintResult.info[rule]) {
outputMsgList.push(Constants.EOL + template);
const occurrenceList = lintResult.info[rule][template];
for (let i = 0; i < occurrenceList.length; i++) {
const occurrence = occurrenceList[i];
outputMsgList.push(
chalk.gray(occurrence.lineNumber) + '\t' +
chalk.cyan('info') + '\t' +
occurrence.message
);
qty++;
}
}
}
return {
outputMsgList,
qty
};
};
const displayVerboseMessage = (message, depth = 0) => {
const config = ConfigUtils.load();
let indentation = '';
for (let i = 0; i < depth; i++) {
indentation += ' ';
}
if (config.verbose) {
console.log(indentation + message);
}
};
module.exports = {
displayOccurrenceList,
displayConfigError,
displayEslintConfigError,
displayInvalidTemplatesPaths,
displayInvalidCommandError,
printExceptionMsg,
displayVerboseMessage
};