1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlimportresolver_p.h"
5
6QT_BEGIN_NAMESPACE
7
8enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
9
10/*
11 Forms complete paths to a module, from a list of base paths,
12 a module URI and version specification.
13
14 For example, QtQml.Models 2.0:
15 - base/QtQml/Models.2.0
16 - base/QtQml.2.0/Models
17 - base/QtQml/Models.2
18 - base/QtQml.2/Models
19 - base/QtQml/Models
20*/
21QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths,
22 QTypeRevision version)
23{
24 static const QLatin1Char Slash('/');
25 static const QLatin1Char Backslash('\\');
26
27 const QVector<QStringView> parts = uri.split(sep: u'.', behavior: Qt::SkipEmptyParts);
28
29 QStringList importPaths;
30 // fully & partially versioned parts + 1 unversioned for each base path
31 importPaths.reserve(asize: 2 * parts.size() + 1);
32
33 auto versionString = [](QTypeRevision version, ImportVersion mode)
34 {
35 if (mode == FullyVersioned) {
36 // extension with fully encoded version number (eg. MyModule.3.2)
37 return QString::fromLatin1(ba: ".%1.%2").arg(a: version.majorVersion())
38 .arg(a: version.minorVersion());
39 }
40 if (mode == PartiallyVersioned) {
41 // extension with encoded version major (eg. MyModule.3)
42 return QString::fromLatin1(ba: ".%1").arg(a: version.majorVersion());
43 }
44 // else extension without version number (eg. MyModule)
45 return QString();
46 };
47
48 auto joinStringRefs = [](const QVector<QStringView> &refs, const QChar &sep) {
49 QString str;
50 for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
51 if (it != refs.cbegin())
52 str += sep;
53 str += *it;
54 }
55 return str;
56 };
57
58 const ImportVersion initial = (version.hasMinorVersion())
59 ? FullyVersioned
60 : (version.hasMajorVersion() ? PartiallyVersioned : Unversioned);
61 for (int mode = initial; mode <= Unversioned; ++mode) {
62 const QString ver = versionString(version, ImportVersion(mode));
63
64 for (const QString &path : basePaths) {
65 QString dir = path;
66 if (!dir.endsWith(c: Slash) && !dir.endsWith(c: Backslash))
67 dir += Slash;
68
69 // append to the end
70 importPaths += dir + joinStringRefs(parts, Slash) + ver;
71
72 if (mode != Unversioned) {
73 // insert in the middle
74 for (int index = parts.size() - 2; index >= 0; --index) {
75 importPaths += dir + joinStringRefs(parts.mid(pos: 0, len: index + 1), Slash)
76 + ver + Slash
77 + joinStringRefs(parts.mid(pos: index + 1), Slash);
78 }
79 }
80 }
81 }
82
83 return importPaths;
84}
85
86QT_END_NAMESPACE
87

source code of qtdeclarative/src/qml/qmldirparser/qqmlimportresolver.cpp