File indexing completed on 2024-05-12 05:51:45
0001 /** 0002 * SPDX-FileCopyrightText: 2023 Waqar Ahmed <waqar.17a@gmail.com> 0003 * SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 #include "eslint.h" 0006 #include "kateproject.h" 0007 0008 #include <KLocalizedString> 0009 0010 #include <QJsonArray> 0011 #include <QJsonDocument> 0012 #include <QJsonObject> 0013 0014 ESLint::ESLint(QObject *parent) 0015 : KateProjectCodeAnalysisTool(parent) 0016 { 0017 } 0018 0019 QString ESLint::name() const 0020 { 0021 return i18n("ESLint"); 0022 } 0023 0024 QString ESLint::description() const 0025 { 0026 return i18n("ESLint is a static analysis tool & style guide enforcer for JavaScript/Typescript code."); 0027 } 0028 0029 QString ESLint::fileExtensions() const 0030 { 0031 return QStringLiteral("js|jsx|ts|tsx"); 0032 } 0033 0034 QStringList ESLint::filter(const QStringList &files) const 0035 { 0036 // js/ts files 0037 return files.filter( 0038 QRegularExpression(QStringLiteral("\\.(") + fileExtensions().replace(QStringLiteral("+"), QStringLiteral("\\+")) + QStringLiteral(")$"))); 0039 } 0040 0041 QString ESLint::path() const 0042 { 0043 return QStringLiteral("npx"); 0044 } 0045 0046 QStringList ESLint::arguments() 0047 { 0048 if (!m_project) { 0049 return {}; 0050 } 0051 0052 QStringList args{ 0053 QStringLiteral("eslint"), 0054 QStringLiteral("-f"), 0055 QStringLiteral("json"), 0056 }; 0057 0058 const QStringList fileList = filter(m_project->files()); 0059 setActualFilesCount(fileList.size()); 0060 return args << fileList; 0061 } 0062 0063 QString ESLint::notInstalledMessage() const 0064 { 0065 return i18n("Please install 'eslint'."); 0066 } 0067 0068 FileDiagnostics ESLint::parseLine(const QString &line) const 0069 { 0070 QJsonParseError e; 0071 QJsonDocument doc = QJsonDocument::fromJson(line.toUtf8(), &e); 0072 if (e.error != QJsonParseError::NoError) { 0073 return {}; 0074 } 0075 0076 const auto arr = doc.array(); 0077 if (arr.empty()) { 0078 return {}; 0079 } 0080 auto obj = arr.at(0).toObject(); 0081 QUrl uri = QUrl::fromLocalFile(obj.value(QStringLiteral("filePath")).toString()); 0082 if (!uri.isValid()) { 0083 return {}; 0084 } 0085 const auto messages = obj.value(QStringLiteral("messages")).toArray(); 0086 if (messages.empty()) { 0087 return {}; 0088 } 0089 0090 QList<Diagnostic> diags; 0091 diags.reserve(messages.size()); 0092 for (const auto &m : messages) { 0093 const auto msg = m.toObject(); 0094 if (msg.isEmpty()) { 0095 continue; 0096 } 0097 const int startLine = msg.value(QStringLiteral("line")).toInt() - 1; 0098 const int startColumn = msg.value(QStringLiteral("column")).toInt() - 1; 0099 const int endLine = msg.value(QStringLiteral("endLine")).toInt() - 1; 0100 const int endColumn = msg.value(QStringLiteral("endColumn")).toInt() - 1; 0101 Diagnostic diag; 0102 diag.range = {startLine, startColumn, endLine, endColumn}; 0103 if (!diag.range.isValid()) { 0104 continue; 0105 } 0106 diag.code = msg.value(QStringLiteral("ruleId")).toString(); 0107 diag.message = msg.value(QStringLiteral("message")).toString(); 0108 diag.source = QStringLiteral("eslint"); 0109 const int severity = msg.value(QStringLiteral("severity")).toInt(); 0110 if (severity == 1) { 0111 diag.severity = DiagnosticSeverity::Warning; 0112 } else if (severity == 2) { 0113 diag.severity = DiagnosticSeverity::Error; 0114 } else { 0115 // fallback, even though there is no other severity 0116 diag.severity = DiagnosticSeverity::Information; 0117 } 0118 diags << diag; 0119 } 0120 return {uri, diags}; 0121 } 0122 0123 QString ESLint::stdinMessages() 0124 { 0125 return QString(); 0126 }