aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmldesigner/designercore/projectstorage/modulescanner.cpp
blob: 2210f0732b3b36ed8904acb99d0a623a47725d79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#include "modulescanner.h"

#ifdef QDS_HAS_QMLPRIVATE
#include <private/qqmldirparser_p.h>
#endif

#include <QDirIterator>
#include <QFile>
#include <QHash>

namespace QmlDesigner {

namespace {

#ifdef QDS_HAS_QMLPRIVATE
std::optional<QString> contentAsQString(const QString &filePath)
{
    QFile file{filePath};
    if (file.open(QIODevice::ReadOnly))
        return {QString::fromUtf8(file.readAll())};

    return {};
}

QString createVersion(const QMultiHash<QString, QQmlDirParser::Component> &components)
{
    auto found = std::max_element(components.begin(), components.end(), [](auto &&first, auto &&second) {
        return first.version < second.version;
    });

    if (found != components.end() && found->version.isValid())
        return QString{"%1.%2"}.arg(found->version.majorVersion()).arg(found->version.minorVersion());

    return {};
}
#endif

} // namespace

void ModuleScanner::scan(const QStringList &modulePaths)
{
    for (const QString &modulePath : modulePaths)
        scan(modulePath.toStdString());
}

void ModuleScanner::scan([[maybe_unused]] std::string_view modulePath)
{
#ifdef QDS_HAS_QMLPRIVATE
    QDirIterator dirIterator{QString::fromUtf8(modulePath), QDir::Dirs, QDirIterator::Subdirectories};

    while (dirIterator.hasNext()) {
        auto directoryPath = dirIterator.next();
        QString qmldirPath = directoryPath + "/qmldir";
        if (QFileInfo::exists(qmldirPath)) {
            QQmlDirParser parser;

            auto content = contentAsQString(qmldirPath);
            if (!content)
                continue;

            bool hasError = parser.parse(*content);
            if (hasError)
                continue;

            auto moduleName = parser.typeNamespace();

            if (moduleName.isEmpty() || m_skip(moduleName))
                continue;

            m_modules.push_back(
                Import::createLibraryImport(moduleName, createVersion(parser.components())));
        }
    }

    std::sort(m_modules.begin(), m_modules.end());
    m_modules.erase(std::unique(m_modules.begin(), m_modules.end()), m_modules.end());
#endif
}

} // namespace QmlDesigner