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: Chris Adams <christopher.adams@nokia.com>
This commit is contained in:
Matthew Vogt 2012-03-14 12:49:36 +10:00 committed by Qt by Nokia
parent 601c7383ab
commit c5cd60a96d
11 changed files with 105 additions and 22 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -390,6 +390,7 @@ public:
QQmlScript::Location location;
QString qualifier;
QString nameSpace;
QQmlScriptBlob *script;
};

View File

@ -0,0 +1,13 @@
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();
}

View File

@ -0,0 +1,5 @@
.import com.nokia.JsModule 1.0 as JsModule
function importedValue() {
return JsModule.ScriptAPI.greeting();
}

View File

@ -0,0 +1,5 @@
var major = 1
var minor = 0
function greeting() { return "Hello" }

View File

@ -0,0 +1 @@
ScriptAPI 1.0 ScriptAPI.js

View File

@ -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()