uxp-linter-test-app
Version:
UXP LINTER is useful for linting your code with ESLint rules and guidelines.
431 lines (380 loc) • 18.2 kB
JavaScript
;
require("v8-compile-cache");
var fs = require('fs'),
utils = require('./utils');
var path = require('path'),
lintIgnore = path.join(__dirname, '.eslintignore'),
packageJson = require('./../package.json'),
constants = require('./constants');
const { fileTypeArray, outputDirectory, rules_category, eslintPrefix } = constants;
const linterDependencies = require('./uxp-linter-dependencies.json');
const installPeerDependencies = utils.isPeerDepsInstallationReqd();
// For starting the configuration for uxp linter
function configureLinter(rl, param, type) {
return new Promise(function (resolve, reject) {
if (param === 'remove') {
uninstallUxpLinter(type).then(() => { resolve(true) });
} else {
installUxpLinter(rl).then(() => { resolve(true) });
}
});
}
async function installUxpLinter(rl = {}) {
await installRequestedLinter(rl);
}
async function installRequestedLinter(rl) {
return new Promise(function (resolve, reject) {
let projectOptions = [];
let uxpDependencies = [...linterDependencies.frameworks];
uxpDependencies.sort(function (opt1, opt2) {
return opt1.seqNo - opt2.seqNo;
});
if ((typeof (rl.question) != 'function')) {
let configData = utils.readLinterConfig();
let projTypeArr = uxpDependencies.filter(obj => obj.type == configData['projectType']);
if (projTypeArr.length <= 0) {
console.error('\x1b[31m%s\x1b[0m', 'No data available!');
process.kill(0);
}
let projTypeObj = projTypeArr[0];
handlePackageInstallationForUxpLinter(rl, projTypeObj, resolve);
} else {
for (let i = 0; i < uxpDependencies.length; i++) {
projectOptions.push({ 'option': uxpDependencies[i].seqNo, 'text': uxpDependencies[i].type });
}
let projTypeMsg = `\nWhich framework does your project use?`;
for (let i = 0; i < projectOptions.length; i++) {
projTypeMsg += '\n' + projectOptions[i].option + '. ' + projectOptions[i].text;
}
projTypeMsg += `\nEnter only one option: `;
rl.question(projTypeMsg, async function (selectedOption) {
let projTypeArr = uxpDependencies.filter(obj => obj.seqNo == selectedOption);
if (projTypeArr.length <= 0) {
console.error('\x1b[31m%s\x1b[0m', 'Invalid option selected!');
process.kill(0);
}
let projTypeObj = projTypeArr[0];
handlePackageInstallationForUxpLinter(rl, projTypeObj, resolve)
});
}
});
}
async function handlePackageInstallationForUxpLinter(rl, projTypeObj, resolve) {
let languageTypeObj = await askLanguageTypeForUxpLinter(rl, projTypeObj);
const updateConfig = {'projectType': projTypeObj.type,
'languageType': languageTypeObj.subType }
await utils.updateLinterConfig(updateConfig);
console.log('\x1b[33m%s\x1b[0m', '\nInstalling required packages. Please wait...');
let installPackageArr = [];
let defaultPackagesArr = linterDependencies.defaultPackages;
if (defaultPackagesArr && defaultPackagesArr.length > 0) {
for (let i = 0; i < defaultPackagesArr.length; i++) {
let packageObj = defaultPackagesArr[i];
let installPackName = packageObj.packageName;
if (packageObj.version && packageObj.version.trim().length > 0) {
installPackName = installPackName + '@' + packageObj.version;
}
installPackageArr.push(installPackName);
if(installPeerDependencies && packageObj.peerDependencies) {
const pkgs = utils.getPackagesList(packageObj.peerDependencies);
installPackageArr.push(...pkgs);
}
}
}
for (let i = 0; i < languageTypeObj.requiredPackages.length; i++) {
let packageObj = languageTypeObj.requiredPackages[i];
let installPackName = packageObj.packageName;
// If dependency has cmd array
if (packageObj.cmd && packageObj.cmd.length > 0) {
for (let j = 0; j < packageObj.cmd.length; j++) {
await require(packageObj.cmd[j]);
}
} else if (packageObj.version && packageObj.version.trim().length > 0) {
installPackName = installPackName + '@' + packageObj.version;
installPackageArr.push(installPackName);
}
if(installPeerDependencies && packageObj.peerDependencies) {
const pkgs = utils.getPackagesList(packageObj.peerDependencies);
installPackageArr.push(...pkgs);
}
}
if (installPackageArr.length > 0) {
await utils.installPackages(installPackageArr, true);
}
// For creating backup of all eslintrc files
await utils.createFileBackup(fileTypeArray, '_backup');
// For Copying New eslint file
let eslintrcFilePath = path.join(__dirname, languageTypeObj.eslintrcPath);
await utils.addConfigFile(eslintrcFilePath, '.eslintrc', true);
await utils.createNewDirectory(outputDirectory);
await utils.addConfigFile(lintIgnore, '.eslintignore', false);
resolve(true);
}
function getInstalledProjectType() {
return new Promise(async function (resolve, reject) {
let rawdata = fs.readFileSync('package.json');
var loadDependancy = JSON.parse(rawdata);
let projectType = null;
if (loadDependancy.config && loadDependancy.config.uxpLinter && loadDependancy.config.uxpLinter.projectType) {
projectType = loadDependancy.config.uxpLinter.projectType;
}
resolve(projectType);
});
}
function getInstalledLanguageType() {
return new Promise(async function (resolve, reject) {
let rawdata = fs.readFileSync('package.json');
var loadDependancy = JSON.parse(rawdata);
let languageType = null;
if (loadDependancy.config && loadDependancy.config.uxpLinter && loadDependancy.config.uxpLinter.languageType) {
languageType = loadDependancy.config.uxpLinter.languageType;
}
resolve(languageType);
});
}
function uninstallUxpLinter(type) {
return new Promise(async function (resolve, reject) {
let removePackageNames = [];
let defaultPackagesArr = linterDependencies.defaultPackages;
if (defaultPackagesArr && defaultPackagesArr.length > 0) {
for (let i = 0; i < defaultPackagesArr.length; i++) {
removePackageNames.push(defaultPackagesArr[i].packageName);
if(installPeerDependencies && defaultPackagesArr[i].peerDependencies) {
const pkgs = utils.getPackagesList(defaultPackagesArr[i].peerDependencies);
removePackageNames.push(...pkgs);
}
}
}
let projectType = await getInstalledProjectType();
let languageType = await getInstalledLanguageType();
if (projectType && languageType) {
let uxpDependencies = [...linterDependencies.frameworks];
let projTypeArr = uxpDependencies.filter(obj => obj.type == projectType);
if (projTypeArr.length > 0) {
let projTypeObj = projTypeArr[0];
let languageTypeArr = projTypeObj.languageType.filter(obj => obj.subType == languageType);
if (languageTypeArr.length > 0) {
let languageTypeObj = languageTypeArr[0];
for (let i = 0; i < languageTypeObj.requiredPackages.length; i++) {
let packageObj = languageTypeObj.requiredPackages[i];
// If dependency has cmd array
if (packageObj.cmd && packageObj.cmd.length > 0) {
for (let j = 0; j < packageObj.cmd.length; j++) {
await require('./scripts/uninstall-cmd-package.js');
}
} else {
removePackageNames.push(packageObj.packageName);
}
}
}
}
}
if (type == 'all') {
removeConfigFiles();
removePackageNames.push(packageJson.name);
}
if (removePackageNames.length > 0) {
await utils.uninstallPackages(removePackageNames);
}
resolve(true);
});
}
async function removeConfigFiles() {
var fileExistEslintrc = fs.existsSync('.eslintrc');
if (fileExistEslintrc) {
fs.unlink('.eslintrc', function (err) {
if (err) throw err;
});
await utils.restoreBackupFile(fileTypeArray, '_backup');
}
var fileExistUxpLintrc = fs.existsSync('.uxplinterrc.json');
if (fileExistUxpLintrc) {
fs.unlink('.uxplinterrc.json', function (err) {
if (err) throw err;
});
await utils.restoreBackupFile(fileTypeArray, '_backup');
}
var fileEslintIgnore = fs.existsSync('.eslintignore');
if (fileEslintIgnore) {
fs.unlink('.eslintignore', function (err) {
if (err) throw err;
});
await utils.restoreBackupFile(['eslintignore'], '_backup');
}
// Need to add once Sonar Integration is implemented
// var fileSonar = fs.existsSync('sonar-project.properties');
// if (fileSonar) {
// fs.unlink('sonar-project.properties', function (err) {
// if (err) throw err;
// });
// await utils.restoreBackupFile(['sonar-project'], '_backup');
// }
}
function runCategoryScript(rl, rules_profile, option) {
return new Promise(async function (resolve, reject) {
let runCategory = false;
const projectType = await utils.getProjectType();
let config = utils.readLinterConfig();
let language = config.languageType.toLowerCase()
let prefix = '';
if (projectType === 'React') {
prefix = `${eslintPrefix}/react`;
runCategory = true;
} else if (projectType === 'Angular') {
prefix = `${eslintPrefix}/angular`;
runCategory = true;
} else if (projectType === 'Vue') {
prefix = `${eslintPrefix}/vue`;
runCategory = true;
} else if (projectType === 'TypeScript') {
prefix = `${eslintPrefix}/typescript`;
runCategory = true;
} else if (projectType === 'Vanilla JS/ES6') {
prefix = `${eslintPrefix}/javascript`;
runCategory = true;
} else {
console.error('\x1b[31m%s\x1b[0m', 'Please install UXP-Linter before selecting any rules.');
resolve(true);
}
if (runCategory) {
let fileExist1 = fs.existsSync('.eslintrc'),
fileExist2 = fs.existsSync('.eslintrc.js'),
getFileName = fileExist1 ? '.eslintrc' : fileExist2 ? '.eslintrc.js' : null,
readRowData,
parsedRowData,
getPromiseData;
if (getFileName) {
readRowData = fs.readFileSync(getFileName);
parsedRowData = JSON.parse(readRowData);
}
switch (rules_profile) {
case 'custom':
let questionForCustomRules = function () {
return new Promise(async function (resolve, reject) {
rl.question("\nPlease enter the path of rules file (File should be in json format): ", function (input) {
let inputFileExist = fs.existsSync(input);
if (!inputFileExist) {
console.log('\x1b[31m%s\x1b[0m', 'Unable to add custom rules! Input file not found.');
resolve(true);
} else {
if (!input.startsWith("./")) {
input = "./" + input;
}
getPromiseData = utils.extendValueIneslint(parsedRowData, option, input);
resolve(true);
}
});
});
}
await questionForCustomRules();
break;
case 'sonar':
getPromiseData = utils.extendValueIneslint(parsedRowData, option, `${eslintPrefix}/sonar-${language}-essential.js`);
break
case `${rules_profile}`:
let filePath;
if (projectType === 'TypeScript' || projectType === 'Vanilla JS/ES6')
filePath = `${prefix}-${rules_profile}.js`;
else
filePath = `${prefix}-${language}-${rules_profile}.js`;
getPromiseData = utils.extendValueIneslint(parsedRowData, option, filePath);
break;
}
let rulesProfile = rules_category.filter(e => e.category === rules_profile);
rulesProfile = rulesProfile && rulesProfile[0] ? rulesProfile[0].label : '';
if (getFileName && !!getPromiseData) {
getPromiseData.then((resolve, reject) => {
utils.updateLinterConfig({'linterProfile': rulesProfile});
let data = JSON.stringify(resolve, null, 4);
fs.writeFileSync(getFileName, data);
}).catch((err) => {
console.error(err);
});
resolve(true);
} else {
resolve(true);
}
}
});
}
function isJsLinterInstalled() {
return new Promise(async function (resolve, reject) {
let configData = utils.readLinterConfig();
if (configData['js-linter'] && configData['projectType'] && configData['languageType']) {
resolve(true);
} else {
resolve(false);
}
});
}
function selectLinterRule(rl, i, options) {
return new Promise(async function (resolve, reject) {
let linterProfile = utils.readLinterConfig('linterProfile');
let initialMessage = `\nPlease select a profile name (Current profile: ${linterProfile}) \n`
let finalMessage = rules_category.reduce((message, currentCategory, index) => {
const { label, description } = currentCategory;
return message + `\n ${(index + 1)}. ${label} (${description})`;
}, initialMessage);
finalMessage += `\n\nPlease provide any one option : `;
rl.question(finalMessage, async function (input) {
let index = parseInt(input) - 1;
if (index > -1 && index < rules_category.length) {
async function showCategoryOption(opt) {
const currentCategory = rules_category.filter(el => el.option === opt)[0];
const { category, label } = currentCategory;
console.log('\x1b[32m%s\x1b[0m', `\n${label} rules profile has been successfully configured for JS Linter.`);
await runCategoryScript(rl, category, i)
}
await showCategoryOption(index);
}
else {
console.log('\x1b[31m%s\x1b[0m', '\nSorry you have entered wrong option. Please try again.');
}
resolve(true);
});
});
}
function askLanguageTypeForUxpLinter(rl, projTypeObj) {
return new Promise(async function (resolve, reject) {
let languageTypeObj;
if ((typeof (rl.question) != 'function')) {
let configData = utils.readLinterConfig();
languageTypeObj = projTypeObj.languageType.filter(obj => obj.subType == configData['languageType'])[0];
} else {
if (projTypeObj.languageType.length == 1) {
languageTypeObj = projTypeObj.languageType[0];
} else if (projTypeObj.languageType.length > 1) {
let languageOptions = [];
for (let i = 0; i < projTypeObj.languageType.length; i++) {
languageOptions.push({ 'option': (i + 1), 'text': projTypeObj.languageType[i].subType });
}
let initMessage = `\nWhat type of language does your project use?`;
for (let i = 0; i < languageOptions.length; i++) {
initMessage += '\n' + languageOptions[i].option + '. ' + languageOptions[i].text;
}
initMessage += `\n\nPlease provide any one option : `;
let questionForlanguageOptionSelection = function () {
return new Promise(async function (resolve, reject) {
rl.question(initMessage, async function (selectedOption) {
let languageEsOptionArr = languageOptions.filter(obj => obj.option == selectedOption);
if (languageEsOptionArr.length <= 0) {
console.error('\x1b[31m%s\x1b[0m', 'You have chosen invalid option. Please try again.');
process.kill(0);
}
let languageEsArr = projTypeObj.languageType.filter(obj => obj.subType == languageEsOptionArr[0].text)
resolve(languageEsArr[0]);
});
});
}
languageTypeObj = await questionForlanguageOptionSelection();
} else {
console.error('\x1b[31m%s\x1b[0m', '\nLanguage type not available for selected project type!');
process.kill(0);
reject();
}
}
resolve(languageTypeObj);
});
}
module.exports = { configureLinter, selectLinterRule, isJsLinterInstalled, getInstalledLanguageType, installUxpLinter }