Commit c5cd60a9 authored by Matthew Vogt's avatar Matthew Vogt Committed by Qt by Nokia

Ensure JS files imported inside modules work correctly

When a module exports functionality provided by a script, ensure
that imported script modules inside that script resolve correctly.

Task-number: QTBUG-24596
Change-Id: I3885dcc56946423f0d7cf00afdcdfaa0cb11967a
Reviewed-by: default avatarChris Adams <christopher.adams@nokia.com>
parent 601c7383
......@@ -295,4 +295,18 @@ QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const
}
#endif
QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component)
{
return debug << qPrintable(QString("{%1 %2.%3}").arg(component.typeName)
.arg(component.majorVersion)
.arg(component.minorVersion));
}
QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script)
{
return debug << qPrintable(QString("{%1 %2.%3}").arg(script.nameSpace)
.arg(script.majorVersion)
.arg(script.minorVersion));
}
QT_END_NAMESPACE
......@@ -55,6 +55,7 @@
#include <QtCore/QUrl>
#include <QtCore/QHash>
#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
......@@ -160,6 +161,8 @@ private:
typedef QList<QQmlDirParser::Component> QQmlDirComponents;
typedef QList<QQmlDirParser::Script> QQmlDirScripts;
QDebug &operator<< (QDebug &, const QQmlDirParser::Component &);
QDebug &operator<< (QDebug &, const QQmlDirParser::Script &);
QT_END_NAMESPACE
......
......@@ -117,7 +117,7 @@ public:
QList<QQmlError> *errors);
QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
bool add(const QQmlDirComponents &qmldircomponentsnetwork,
QString add(const QQmlDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix,
int vmaj, int vmin, QQmlScript::Import::Type importType,
QQmlImportDatabase *database, QList<QQmlError> *errors);
......@@ -493,7 +493,7 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
return stableRelativePath;
}
bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
const QString& uri_arg, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
QQmlImportDatabase *database, QList<QQmlError> *errors)
......@@ -540,7 +540,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
return false;
return QString();
break;
}
}
......@@ -564,7 +564,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(fi.absolutePath()).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
return false;
return QString();
break;
}
}
......@@ -586,7 +586,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
url = QUrl::fromLocalFile(absolutePath).toString();
uri = resolvedUri(dir, database);
if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
return false;
return QString();
break;
}
}
......@@ -604,7 +604,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg));
errors->prepend(error);
}
return false;
return QString();
}
} else {
if (importType == QQmlScript::Import::File && qmldircomponents.isEmpty()) {
......@@ -619,14 +619,14 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setUrl(QUrl(importUrl));
errors->prepend(error);
}
return false; // local import dirs must exist
return QString(); // local import dirs must exist
}
uri = resolvedUri(dir, database);
if (uri.endsWith(Slash))
uri.chop(1);
if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,&qmldirscripts,errors))
return false;
return QString();
}
} else {
if (prefix.isEmpty()) {
......@@ -642,7 +642,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setUrl(QUrl(importUrl));
errors->prepend(error);
}
return false;
return QString();
}
}
}
......@@ -669,7 +669,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
errors->prepend(error);
}
return false;
return QString();
}
}
......@@ -686,7 +686,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url));
errors->prepend(error);
return false;
return QString();
}
}
......@@ -716,7 +716,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork,
s->imports.prepend(data);
return true;
return data.url;
}
bool QQmlImportsPrivate::find(const QString& type, int *vmajor, int *vminor, QQmlType** type_return,
......@@ -874,9 +874,11 @@ QQmlImportDatabase::~QQmlImportDatabase()
The \a prefix may be empty, in which case the import location is considered for
unqualified types.
Returns the resolved URL of the import on success.
The base URL must already have been set with Import::setBaseUrl().
*/
bool QQmlImports::addImport(QQmlImportDatabase *importDb,
QString QQmlImports::addImport(QQmlImportDatabase *importDb,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
const QQmlDirComponents &qmldircomponentsnetwork,
......
......@@ -93,7 +93,7 @@ public:
QQmlType** type_return, QString* url_return,
int *version_major, int *version_minor) const;
bool addImport(QQmlImportDatabase *,
QString addImport(QQmlImportDatabase *,
const QString& uri, const QString& prefix, int vmaj, int vmin,
QQmlScript::Import::Type importType,
const QQmlDirComponents &qmldircomponentsnetwork,
......
......@@ -1558,7 +1558,6 @@ void QQmlTypeData::dataReceived(const QByteArray &data)
ref.qualifier = import.qualifier;
ref.script = blob;
m_scripts << ref;
}
}
......@@ -1657,8 +1656,8 @@ void QQmlTypeData::resolveTypes()
import.extractVersion(&vmaj, &vmin);
QList<QQmlError> errors;
if (!m_imports.addImport(importDatabase, import.uri, import.qualifier,
vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) {
if (m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
import.type, qmldircomponentsnetwork, &errors).isNull()) {
QQmlError error;
if (errors.size()) {
error = errors.takeFirst();
......@@ -1859,8 +1858,9 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data)
import.extractVersion(&vmaj, &vmin);
QList<QQmlError> errors;
if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
import.type, QQmlDirComponents(), &errors)) {
QString importUrl = m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin,
import.type, QQmlDirComponents(), &errors);
if (importUrl.isNull()) {
QQmlError error = errors.takeFirst();
// description should be set by addImport().
error.setUrl(m_imports.baseUrl());
......@@ -1871,6 +1871,22 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data)
setError(errors);
return;
}
// Does this library contain any scripts?
QUrl libraryUrl(importUrl);
const QQmlDirParser *dirParser = typeLoader()->qmlDirParser(libraryUrl.path() + QLatin1String("qmldir"));
foreach (const QQmlDirParser::Script &script, dirParser->scripts()) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
addDependency(blob);
ScriptReference ref;
ref.location = import.location.start;
ref.qualifier = script.nameSpace;
ref.nameSpace = import.qualifier;
ref.script = blob;
m_scripts << ref;
}
}
}
}
......@@ -1902,11 +1918,20 @@ void QQmlScriptBlob::done()
m_scriptData->urlString = finalUrlString();
m_scriptData->importCache = new QQmlTypeNameCache();
for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
QSet<QString> ns;
for (int scriptIndex = 0; !isError() && scriptIndex < m_scripts.count(); ++scriptIndex) {
const ScriptReference &script = m_scripts.at(scriptIndex);
m_scriptData->scripts.append(script.script);
m_scriptData->importCache->add(script.qualifier, ii);
if (!script.nameSpace.isNull()) {
if (!ns.contains(script.nameSpace)) {
ns.insert(script.nameSpace);
m_scriptData->importCache->add(script.nameSpace);
}
}
m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
m_imports.populateCache(m_scriptData->importCache, engine);
......
......@@ -390,6 +390,7 @@ public:
QQmlScript::Location location;
QString qualifier;
QString nameSpace;
QQmlScriptBlob *script;
};
......
import QtQuick 2.0
import com.nokia.JsModule 1.0
import com.nokia.JsModule 1.0 as RenamedModule
import "testJsModuleImport.js" as TestJsModuleImport
QtObject {
id: testQtObject
property string importedScriptStringValue: ScriptAPI.greeting();
property string renamedScriptStringValue: RenamedModule.ScriptAPI.greeting();
property string reimportedScriptStringValue: TestJsModuleImport.importedValue();
}
.import com.nokia.JsModule 1.0 as JsModule
function importedValue() {
return JsModule.ScriptAPI.greeting();
}
var major = 1
var minor = 0
function greeting() { return "Hello" }
......@@ -254,6 +254,9 @@ void tst_qqmlecmascript::initTestCase()
{
QQmlDataTest::initTestCase();
registerTypes();
QString dataDir(dataDirectory() + QLatin1Char('/') + QLatin1String("lib"));
engine.addImportPath(dataDir);
}
void tst_qqmlecmascript::assignBasicTypes()
......@@ -3298,6 +3301,17 @@ void tst_qqmlecmascript::importScripts_data()
<< QStringList()
<< (QStringList() << QLatin1String("testValue"))
<< (QVariantList() << QVariant(20));
QTest::newRow("import module which exports a script")
<< testFileUrl("jsimport/testJsImport.qml")
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("importedScriptStringValue")
<< QLatin1String("renamedScriptStringValue")
<< QLatin1String("reimportedScriptStringValue"))
<< (QVariantList() << QVariant(QString("Hello"))
<< QVariant(QString("Hello"))
<< QVariant(QString("Hello")));
}
void tst_qqmlecmascript::importScripts()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment