File indexing completed on 2024-12-29 04:49:58
0001 /* 0002 SPDX-FileCopyrightText: 2017-2021 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "scriptextractor.h" 0008 #include "extractorscriptengine_p.h" 0009 #include "logging.h" 0010 0011 #include <KItinerary/ExtractorDocumentNode> 0012 #include <KItinerary/ExtractorEngine> 0013 #include <KItinerary/ExtractorFilter> 0014 #include <KItinerary/ExtractorResult> 0015 0016 #include <QFile> 0017 #include <QFileInfo> 0018 #include <QJsonArray> 0019 #include <QJsonObject> 0020 0021 using namespace KItinerary; 0022 0023 namespace KItinerary { 0024 class ScriptExtractorPrivate 0025 { 0026 public: 0027 QString m_mimeType; 0028 QString m_fileName; 0029 QString m_scriptName; 0030 QString m_scriptFunction; 0031 std::vector<ExtractorFilter> m_filters; 0032 int m_index = -1; 0033 }; 0034 } 0035 0036 ScriptExtractor::ScriptExtractor() 0037 : d(std::make_unique<ScriptExtractorPrivate>()) 0038 { 0039 } 0040 0041 ScriptExtractor::~ScriptExtractor() = default; 0042 0043 bool ScriptExtractor::load(const QJsonObject &obj, const QString &fileName, int index) 0044 { 0045 d->m_fileName = fileName; 0046 d->m_index = index; 0047 0048 d->m_mimeType = obj.value(QLatin1StringView("mimeType")).toString(); 0049 0050 const auto filterArray = obj.value(QLatin1StringView("filter")).toArray(); 0051 for (const auto &filterValue : filterArray) { 0052 ExtractorFilter f; 0053 if (!f.load(filterValue.toObject())) { 0054 qCDebug(Log) << "invalid filter expression:" << fileName; 0055 return false; 0056 } 0057 d->m_filters.push_back(std::move(f)); 0058 } 0059 0060 const auto scriptName = obj.value(QLatin1StringView("script")).toString(); 0061 if (!scriptName.isEmpty()) { 0062 QFileInfo fi(fileName); 0063 d->m_scriptName = fi.path() + QLatin1Char('/') + scriptName; 0064 } 0065 0066 if (!d->m_scriptName.isEmpty() && !QFile::exists(d->m_scriptName)) { 0067 qCWarning(Log) << "Script file not found:" << d->m_scriptName; 0068 return false; 0069 } 0070 d->m_scriptFunction = obj.value(QLatin1StringView("function")) 0071 .toString(QStringLiteral("main")); 0072 0073 return !d->m_filters.empty() && !d->m_mimeType.isEmpty(); 0074 } 0075 0076 QJsonObject ScriptExtractor::toJson() const 0077 { 0078 QJsonObject obj; 0079 obj.insert(QStringLiteral("mimeType"), d->m_mimeType); 0080 0081 QFileInfo metaFi(d->m_fileName); 0082 QFileInfo scriptFi(d->m_scriptName); 0083 if (metaFi.canonicalPath() == scriptFi.canonicalPath()) { 0084 obj.insert(QStringLiteral("script"), scriptFi.fileName()); 0085 } else { 0086 obj.insert(QStringLiteral("script"), d->m_scriptName); 0087 } 0088 obj.insert(QStringLiteral("function"), d->m_scriptFunction); 0089 0090 QJsonArray filters; 0091 std::transform(d->m_filters.begin(), d->m_filters.end(), std::back_inserter(filters), std::mem_fn(&ExtractorFilter::toJson)); 0092 obj.insert(QStringLiteral("filter"), filters); 0093 0094 return obj; 0095 } 0096 0097 QString ScriptExtractor::name() const 0098 { 0099 QFileInfo fi(d->m_fileName); 0100 if (d->m_index < 0) { 0101 return fi.baseName(); 0102 } 0103 return fi.baseName() + QLatin1Char(':') + QString::number(d->m_index); 0104 } 0105 0106 QString ScriptExtractor::mimeType() const 0107 { 0108 return d->m_mimeType; 0109 } 0110 0111 void ScriptExtractor::setMimeType(const QString &mimeType) 0112 { 0113 d->m_mimeType = mimeType; 0114 } 0115 0116 QString ScriptExtractor::scriptFileName() const 0117 { 0118 return d->m_scriptName; 0119 } 0120 0121 void ScriptExtractor::setScriptFileName(const QString &script) 0122 { 0123 d->m_scriptName = script; 0124 } 0125 0126 QString ScriptExtractor::scriptFunction() const 0127 { 0128 return d->m_scriptFunction; 0129 } 0130 0131 void ScriptExtractor::setScriptFunction(const QString &func) 0132 { 0133 d->m_scriptFunction = func; 0134 } 0135 0136 QString ScriptExtractor::fileName() const 0137 { 0138 return d->m_fileName; 0139 } 0140 0141 const std::vector<ExtractorFilter>& ScriptExtractor::filters() const 0142 { 0143 return d->m_filters; 0144 } 0145 0146 void ScriptExtractor::setFilters(std::vector<ExtractorFilter> &&filters) 0147 { 0148 d->m_filters = std::move(filters); 0149 } 0150 0151 void ScriptExtractor::setFilters(const std::vector<ExtractorFilter> &filters) 0152 { 0153 d->m_filters = filters; 0154 } 0155 0156 bool ScriptExtractor::canHandle(const ExtractorDocumentNode &node) const 0157 { 0158 if (node.mimeType() != d->m_mimeType) { 0159 return false; 0160 } 0161 0162 // no filters matches always 0163 if (d->m_filters.empty()) { 0164 return true; 0165 } 0166 0167 return std::any_of(d->m_filters.begin(), d->m_filters.end(), [&node](const auto &filter) { 0168 return filter.matches(node); 0169 }); 0170 } 0171 0172 ExtractorResult ScriptExtractor::extract(const ExtractorDocumentNode &node, const ExtractorEngine *engine) const 0173 { 0174 std::vector<ExtractorDocumentNode> triggerNodes; 0175 for (const auto &filter : d->m_filters) { 0176 if (filter.scope() != ExtractorFilter::Current) { 0177 filter.allMatches(node, triggerNodes); 0178 } 0179 } 0180 0181 if (triggerNodes.empty()) { 0182 return engine->scriptEngine()->execute(this, node, node); 0183 } else { 0184 ExtractorResult result; 0185 for (const auto &triggerNode : triggerNodes) { 0186 result.append(engine->scriptEngine()->execute(this, node, triggerNode)); 0187 } 0188 return result; 0189 } 0190 }