QmlDom: Remove the standalone version of QmlDom
Change-Id: I2582f3ca0217ec9791ead71393cfa506c28086b8 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
757f50166b
commit
b153740606
|
@ -1,69 +0,0 @@
|
|||
type: Group
|
||||
instructions:
|
||||
- type: SetBuildDirectory
|
||||
directory: "{{.SourceDir}}/examples/qml/qmldom"
|
||||
- type: MakeDirectory
|
||||
directory: "{{.BuildDir}}/qt63"
|
||||
- type: ChangeDirectory
|
||||
directory: "{{.BuildDir}}/qt63"
|
||||
- type: EnvironmentVariable
|
||||
variableName: CONFIGURE_ENV_PREFIX
|
||||
variableValue: "{{.Env.ENV_PREFIX}}"
|
||||
- type: ExecuteCommand
|
||||
command: "curl -s https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-beta2-released/Qt/qtbase/qtbase-MacOS-MacOS_12-Clang-MacOS-MacOS_12-X86_64-ARM64.7z -o qtbase.7z"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
download of https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-beta2-released/Qt/qtbase/qtbase-MacOS-MacOS_12-Clang-MacOS-MacOS_12-X86_64-ARM64.7z failed
|
||||
- type: ExecuteCommand
|
||||
command: "curl -s https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-beta2-released/Qt/qtdeclarative/qtdeclarative-MacOS-MacOS_12-Clang-MacOS-MacOS_12-X86_64-ARM64.7z -o qtdeclarative.7z"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
Download of https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-beta2-released/Qt/qtdeclarative/qtdeclarative-MacOS-MacOS_12-Clang-MacOS-MacOS_12-X86_64-ARM64.7z failed
|
||||
- type: ExecuteCommand
|
||||
command: "7za x qtbase.7z"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
Uncompress of qtbase failed.
|
||||
- type: ExecuteCommand
|
||||
command: "7za x qtdeclarative.7z"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
Uncompress of qtdeclarative failed.
|
||||
- type: ExecuteCommand
|
||||
command: "{{.Env.ENV_PREFIX}} cmake -S {{.SourceDir}}/examples/qml/qmldom -B standalone63 -DCMAKE_PREFIX_PATH={{.BuildDir}}/qt63"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
configuration of qmldom standalone on Qt 6.5 failed
|
||||
- type: ExecuteCommand
|
||||
command: "{{.Env.ENV_PREFIX}} cmake --build standalone63"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 3600
|
||||
maxTimeBetweenOutput: 1800
|
||||
userMessageOnFailure: >
|
||||
Compilation of qmldom standalone on Qt 6.5 FAILED, see the log for details.
|
||||
- type: ExecuteCommand
|
||||
command: "./standalone63/qmldomloadeditwrite"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
Run of qmldom standalone on Qt 6.5 FAILED
|
||||
enable_if:
|
||||
condition: and
|
||||
conditions:
|
||||
- condition: property
|
||||
property: target.arch
|
||||
contains_value: X86_64
|
||||
- condition: property
|
||||
property: target.os
|
||||
contains_value: MacOS
|
|
@ -1,75 +0,0 @@
|
|||
type: Group
|
||||
instructions:
|
||||
- type: SetBuildDirectory
|
||||
directory: "{{.SourceDir}}/examples/qml/qmldom"
|
||||
- type: MakeDirectory
|
||||
directory: "{{.BuildDir}}/qt63"
|
||||
- type: ChangeDirectory
|
||||
directory: "{{.BuildDir}}/qt63"
|
||||
- type: EnvironmentVariable
|
||||
variableName: CONFIGURE_ENV_PREFIX
|
||||
variableValue: "{{.Env.ENV_PREFIX}}"
|
||||
- type: ExecuteCommand
|
||||
command: "curl -s https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-beta2-released/Qt/qtbase/qtbase-Windows-Windows_10_22H2-MSVC2019-Windows-Windows_10_22H2-X86_64.7z -o qtbase.7z"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
download of https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-beta2-released/Qt/qtbase/qtbase-Windows-Windows_10_22H2-MSVC2019-Windows-Windows_10_22H2-X86_64.7z failed
|
||||
- type: ExecuteCommand
|
||||
command: "curl -s https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-beta2-released/Qt/qtdeclarative/qtdeclarative-Windows-Windows_10_22H2-MSVC2019-Windows-Windows_10_22H2-X86_64.7z -o qtdeclarative.7z"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
Download of https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-beta2-released/Qt/qtdeclarative/qtdeclarative-Windows-Windows_10_22H2-MSVC2019-Windows-Windows_10_22H2-X86_64.7z failed
|
||||
- type: ExecuteCommand
|
||||
command: "7z.exe x qtbase.7z"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
Uncompress of qtbase failed.
|
||||
- type: ExecuteCommand
|
||||
command: "7z.exe x qtdeclarative.7z"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
Uncompress of qtdeclarative failed.
|
||||
- type: ExecuteCommand
|
||||
command: "{{.Env.ENV_PREFIX}} cmake -S {{.SourceDir}}/examples/qml/qmldom -B standalone63 -DCMAKE_PREFIX_PATH={{.BuildDir}}/qt63"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
configuration of qmldom standalone on Qt 6.5 failed
|
||||
- type: ExecuteCommand
|
||||
command: "{{.Env.ENV_PREFIX}} cmake --build standalone63"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 3600
|
||||
maxTimeBetweenOutput: 1800
|
||||
userMessageOnFailure: >
|
||||
Compilation of qmldom standalone on Qt 6.5 FAILED, see the log for details.
|
||||
- type: PrependToEnvironmentVariable
|
||||
variableName: PATH
|
||||
variableValue: "{{.BuildDir}}/qt63/bin;"
|
||||
- type: ExecuteCommand
|
||||
command: "./standalone63/qmldomloadeditwrite"
|
||||
ignoreExitCode: false
|
||||
maxTimeInSeconds: 1800
|
||||
maxTimeBetweenOutput: 900
|
||||
userMessageOnFailure: >
|
||||
Run of qmldom standalone on Qt 6.5 FAILED
|
||||
enable_if:
|
||||
condition: and
|
||||
conditions:
|
||||
- condition: property
|
||||
property: target.arch
|
||||
contains_value: X86_64
|
||||
- condition: property
|
||||
property: target.os
|
||||
contains_value: Windows
|
||||
- condition: property
|
||||
property: target.compiler
|
||||
contains_value: MSVC
|
|
@ -17,5 +17,3 @@ instructions:
|
|||
Test:
|
||||
- !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml"
|
||||
- !include "{{qt/qtbase}}/coin_module_test_docs.yaml"
|
||||
- !include "{{qt/qtdeclarative}}/coin_dom_standalone_old_qt_mac.yaml"
|
||||
- !include "{{qt/qtdeclarative}}/coin_dom_standalone_old_qt_win.yaml"
|
||||
|
|
|
@ -28,11 +28,7 @@
|
|||
#include <QtCore/QMutexLocker>
|
||||
#include <QtCore/QPair>
|
||||
|
||||
#ifdef QMLDOM_STANDALONE
|
||||
# include "qmlcompiler/qqmljsscope_p.h"
|
||||
#else
|
||||
# include <private/qqmljsscope_p.h>
|
||||
#endif
|
||||
#include <private/qqmljsscope_p.h>
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
|
|
@ -9,11 +9,7 @@
|
|||
#include <QtQml/private/qqmljsparser_p.h>
|
||||
#include <QtQml/private/qqmljslexer_p.h>
|
||||
#include <QtQml/private/qqmljsengine_p.h>
|
||||
#ifdef QMLDOM_STANDALONE
|
||||
# include "qmlcompiler/qqmljstypedescriptionreader_p.h"
|
||||
#else
|
||||
# include <private/qqmljstypedescriptionreader_p.h>
|
||||
#endif
|
||||
#include <private/qqmljstypedescriptionreader_p.h>
|
||||
|
||||
#include <QtCore/qdir.h>
|
||||
|
||||
|
|
|
@ -20,13 +20,9 @@
|
|||
|
||||
// for Q_DECLARE_TR_FUNCTIONS
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#ifdef QMLDOM_STANDALONE
|
||||
# include "qmlcompiler/qqmljsmetatypes_p.h"
|
||||
# include "qmlcompiler/qqmljsscope_p.h"
|
||||
#else
|
||||
# include <private/qqmljsmetatypes_p.h>
|
||||
# include <private/qqmljsscope_p.h>
|
||||
#endif
|
||||
#include <private/qqmljsmetatypes_p.h>
|
||||
#include <private/qqmljsscope_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QQmlJS {
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include(../../../.cmake.conf)
|
||||
project(standalone_qmldom LANGUAGES CXX VERSION "${QT_REPO_MODULE_VERSION}")
|
||||
option(QMLDOM_EXTERNAL_BUILD "If the build is against an external Qt, and not tested inside a build of this Qt" ON)
|
||||
|
||||
if (QMLDOM_EXTERNAL_BUILD)
|
||||
find_package(Qt6 COMPONENTS Core Qml)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
|
||||
elseif (MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
|
||||
endif()
|
||||
|
||||
|
||||
add_library(qmldomlib
|
||||
STATIC
|
||||
private/qtqmlcompilerexports_p.h
|
||||
../../qmlcompiler/qcoloroutput.cpp ../../qmlcompiler/qcoloroutput_p.h
|
||||
../../qmlcompiler/qdeferredpointer_p.h
|
||||
../../qmlcompiler/qqmljsannotation.cpp ../../qmlcompiler/qqmljsannotation_p.h
|
||||
../../qmlcompiler/qqmljsimporter.cpp ../../qmlcompiler/qqmljsimporter_p.h
|
||||
../../qmlcompiler/qqmljsimportvisitor.cpp ../../qmlcompiler/qqmljsimportvisitor_p.h
|
||||
../../qmlcompiler/qqmljslogger.cpp ../../qmlcompiler/qqmljslogger_p.h
|
||||
../../qmlcompiler/qqmljsmetatypes.cpp ../../qmlcompiler/qqmljsmetatypes_p.h
|
||||
../../qmlcompiler/qqmljsresourcefilemapper.cpp ../../qmlcompiler/qqmljsresourcefilemapper_p.h
|
||||
../../qmlcompiler/qqmljsscope.cpp ../../qmlcompiler/qqmljsscope_p.h
|
||||
../../qmlcompiler/qqmljsscopesbyid_p.h
|
||||
../../qmlcompiler/qqmljsutils.cpp ../../qmlcompiler/qqmljsutils_p.h
|
||||
../../qmlcompiler/qqmljstypedescriptionreader.cpp ../../qmlcompiler/qqmljstypedescriptionreader_p.h
|
||||
../../qmlcompiler/qqmljstypereader.cpp ../../qmlcompiler/qqmljstypereader_p.h
|
||||
../../qmlcompiler/qqmljstyperesolver.cpp ../../qmlcompiler/qqmljstyperesolver_p.h
|
||||
../../qmlcompiler/qqmljsregistercontent.cpp ../../qmlcompiler/qqmljsregistercontent_p.h
|
||||
../qqmldom_fwd_p.h
|
||||
../qqmldom_global.h
|
||||
../qqmldomastcreator.cpp ../qqmldomastcreator_p.h
|
||||
../qqmldomastdumper.cpp ../qqmldomastdumper_p.h
|
||||
../qqmldomattachedinfo.cpp ../qqmldomattachedinfo_p.h
|
||||
../qqmldomcodeformatter.cpp ../qqmldomcodeformatter_p.h
|
||||
../qqmldomcomments.cpp ../qqmldomcomments_p.h
|
||||
../qqmldomcompare.cpp ../qqmldomcompare_p.h
|
||||
../qqmldomconstants_p.h
|
||||
../qqmldomelements.cpp ../qqmldomelements_p.h
|
||||
../qqmldomscriptelements.cpp ../qqmldomscriptelements_p.h
|
||||
../qqmldomerrormessage.cpp ../qqmldomerrormessage_p.h
|
||||
../qqmldomexternalitems.cpp ../qqmldomexternalitems_p.h
|
||||
../qqmldomfieldfilter.cpp ../qqmldomfieldfilter_p.h
|
||||
../qqmldomfilewriter.cpp ../qqmldomfilewriter_p.h
|
||||
../qqmldomfunctionref_p.h
|
||||
../qqmldomitem.cpp ../qqmldomitem_p.h
|
||||
../qqmldomlinewriter.cpp ../qqmldomlinewriter_p.h
|
||||
../qqmldommock.cpp ../qqmldommock_p.h
|
||||
../qqmldommoduleindex.cpp ../qqmldommoduleindex_p.h
|
||||
../qqmldomoutwriter.cpp ../qqmldomoutwriter_p.h
|
||||
../qqmldompath.cpp ../qqmldompath_p.h
|
||||
../qqmldomreformatter.cpp ../qqmldomreformatter_p.h
|
||||
../qqmldomscanner.cpp ../qqmldomscanner_p.h
|
||||
../qqmldomstringdumper.cpp ../qqmldomstringdumper_p.h
|
||||
../qqmldomtop.cpp ../qqmldomtop_p.h
|
||||
../qqmldomtypesreader.cpp ../qqmldomtypesreader_p.h
|
||||
)
|
||||
if(NOT QMLDOM_EXTERNAL_BUILD)
|
||||
qt_autogen_tools_initial_setup(qmldomlib)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(qmldomlib PUBLIC QMLDOM_STANDALONE)
|
||||
|
||||
target_include_directories(qmldomlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../..)
|
||||
target_link_libraries(qmldomlib
|
||||
PUBLIC
|
||||
Qt::CorePrivate
|
||||
Qt::QmlPrivate
|
||||
Qt::QmlCompilerPrivate
|
||||
)
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "../qqmldom_global.h"
|
||||
#ifndef QTQMLCOMPILEREXPORTS_P_H
|
||||
#define QTQMLCOMPILEREXPORTS_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#define Q_QMLCOMPILER_PRIVATE_EXPORT QMLDOM_EXPORT
|
||||
#endif
|
|
@ -10,4 +10,3 @@ add_subdirectory(stringdumper)
|
|||
add_subdirectory(merging)
|
||||
add_subdirectory(reformatter)
|
||||
add_subdirectory(combined)
|
||||
add_subdirectory(standalone)
|
||||
|
|
|
@ -20,7 +20,6 @@ qt_internal_add_test(tst_dom_all
|
|||
../domitem/tst_qmldomitem.h
|
||||
../merging/tst_dommerging.h
|
||||
../reformatter/tst_reformatter.h
|
||||
../standalone/tst_standalone.h
|
||||
INCLUDE_DIRECTORIES
|
||||
..
|
||||
DEFINES
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "merging/tst_dommerging.h"
|
||||
#include "path/tst_qmldompath.h"
|
||||
#include "reformatter/tst_reformatter.h"
|
||||
#include "standalone/tst_standalone.h"
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
|
@ -38,10 +37,6 @@ int main(int argc, char *argv[])
|
|||
QQmlJS::Dom::TestReformatter test;
|
||||
status |= QTest::qExec(&test, argc, argv);
|
||||
}
|
||||
{
|
||||
QQmlJS::Dom::TestStandalone test;
|
||||
status |= QTest::qExec(&test, argc, argv);
|
||||
}
|
||||
if (status)
|
||||
qWarning() << "Combined test failed!";
|
||||
return status;
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_dom_all Binary executing all tests together
|
||||
## (simpler to verify coverage)
|
||||
#####################################################################
|
||||
# Collect test data
|
||||
file(GLOB_RECURSE test_data_glob
|
||||
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
domdata/*)
|
||||
list(APPEND test_data ${test_data_glob})
|
||||
|
||||
set(QMLDOM_EXTERNAL_BUILD OFF CACHE BOOL "If the build is against an external Qt, and not tested inside a build of this Qt" FORCE)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/qmldom/standalone qmldomlib)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
|
||||
elseif (MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
|
||||
endif()
|
||||
|
||||
qt_internal_add_test(tst_standalone
|
||||
SOURCES
|
||||
tst_standalone.cpp
|
||||
DEFINES
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/../domdata"
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
Qt::QmlPrivate
|
||||
qmldomlib
|
||||
TESTDATA ${test_data}
|
||||
)
|
||||
|
||||
qt_internal_extend_target(tst_standalone CONDITION ANDROID OR IOS
|
||||
DEFINES
|
||||
QT_QMLTEST_DATADIR=":/domdata"
|
||||
)
|
|
@ -1,5 +0,0 @@
|
|||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "tst_standalone.h"
|
||||
QTEST_MAIN(QQmlJS::Dom::TestStandalone)
|
|
@ -1,634 +0,0 @@
|
|||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#ifdef QMLDOM_STANDALONE
|
||||
# include "qmldom/qqmldom_global.h"
|
||||
// common declarations
|
||||
# include "qmldom/qqmldomitem_p.h"
|
||||
// comparisons of two DomItems
|
||||
# include "qmldom/qqmldomcompare_p.h"
|
||||
// field filters to compare only selected fields (ignore for example location changes)
|
||||
# include "qmldom/qqmldomfieldfilter_p.h"
|
||||
// needed to edit and cast to concrete type (PropertyDefinition, ScriptExpression,...)
|
||||
# include "qmldom/qqmldomelements_p.h"
|
||||
// cast of the top level items (DomEnvironments,...)
|
||||
# include "qmldom/qqmldomtop_p.h"
|
||||
#else
|
||||
# include <QtQmlDom/qqmldom_global.h>
|
||||
// common declarations
|
||||
# include <QtQmlDom/private/qqmldomitem_p.h>
|
||||
// comparisons of two DomItems
|
||||
# include <QtQmlDom/private/qqmldomcompare_p.h>
|
||||
// field filters to compare only selected fields (ignore for example location changes)
|
||||
# include <QtQmlDom/private/qqmldomfieldfilter_p.h>
|
||||
// needed to edit and cast to concrete type (PropertyDefinition, ScriptExpression,...)
|
||||
# include <QtQmlDom/private/qqmldomelements_p.h>
|
||||
// cast of the top level items (DomEnvironments,...)
|
||||
# include <QtQmlDom/private/qqmldomtop_p.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QLatin1String>
|
||||
#include <QLatin1Char>
|
||||
#include <QLibraryInfo>
|
||||
#include <QDir>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace QQmlJS {
|
||||
namespace Dom {
|
||||
|
||||
class TestStandalone : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testLoadEditSave()
|
||||
{
|
||||
QString baseDir = QLatin1String(QT_QMLTEST_DATADIR) + QLatin1String("/reformatter");
|
||||
QStringList qmltypeDirs =
|
||||
QStringList({ baseDir, QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath) });
|
||||
|
||||
// qDebug() << "Creating an environment loading qml from the directories" << qmltypeDirs;
|
||||
// qDebug() << "single threaded, no dependencies";
|
||||
DomItem env = DomEnvironment::create(
|
||||
qmltypeDirs,
|
||||
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
||||
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
||||
|
||||
QString testFilePath = baseDir + QLatin1String("/file1.qml");
|
||||
DomItem tFile; // place where to store the loaded file
|
||||
|
||||
// qDebug() << "loading the file" << testFilePath;
|
||||
env.loadFile(
|
||||
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), testFilePath),
|
||||
[&tFile](Path, const DomItem &, const DomItem &newIt) {
|
||||
tFile = newIt; // callback called when everything is loaded that receives the
|
||||
// loaded external file pair (path, oldValue, newValue)
|
||||
},
|
||||
LoadOption::DefaultLoad);
|
||||
|
||||
// trigger the load
|
||||
env.loadPendingDependencies();
|
||||
|
||||
// # Read only API: DomItem is a generic pointer for read only access to Dom Itmes :)
|
||||
{
|
||||
// ## declarative json like API
|
||||
DomItem qmlFile = tFile.field(Fields::currentItem);
|
||||
DomItem imports = qmlFile.field(Fields::imports);
|
||||
DomItem qmlObj = qmlFile.field(Fields::components)
|
||||
.key(QString())
|
||||
.index(0)
|
||||
.field(Fields::objects)
|
||||
.index(0);
|
||||
|
||||
// ### Dump
|
||||
// any DomItem can be dumped
|
||||
// qDebug() << "writing to QDebug dumps that element:" << imports;
|
||||
// often the dump is too verbose, and one might want it to a separate file
|
||||
QString dumpFilePath = QDir(QDir::tempPath())
|
||||
.filePath(QFileInfo(testFilePath).baseName()
|
||||
+ QLatin1String(".dump.json"));
|
||||
qmlFile.dump(dumpFilePath, FieldFilter::defaultFilter());
|
||||
// qDebug() << "dumped file to" << dumpFilePath;
|
||||
|
||||
// ### Paths
|
||||
// qDebug() << "To identify a DomItem a canonical path can be used:"
|
||||
// << imports.canonicalPath();
|
||||
// a path can be converted to/from strings
|
||||
QString pString = imports.canonicalPath().toString();
|
||||
Path importsPath = Path::fromString(pString);
|
||||
// and loaded again using the .path(somePath) method
|
||||
DomItem imports2 = env.path(importsPath);
|
||||
QCOMPARE(imports, imports2);
|
||||
// the canonical path is absolute, but you can have relative paths
|
||||
Path first = Path::Index(0);
|
||||
DomItem firstImport = imports.path(first);
|
||||
// an existing path can also be extended
|
||||
Path firstImportPath = importsPath.index(0);
|
||||
QCOMPARE(firstImportPath, firstImport.canonicalPath());
|
||||
// the normal elements of a path are index, key, field
|
||||
// Uppercase static method creates one, lowercase appends to an existing path.
|
||||
Path mainComponentPath = Path::Field(Fields::components).key("").index(0);
|
||||
DomItem mainComponent = qmlFile.path(mainComponentPath);
|
||||
// DomItems have the same methods to access their elements
|
||||
DomItem mainComponent2 = qmlFile.field(Fields::components).key("").index(0);
|
||||
// two other special ements are root (root element for absolute paths)
|
||||
Path topPath = Path::Root(PathRoot::Top);
|
||||
QCOMPARE(topPath, importsPath[0]);
|
||||
// the current element performs an operation (tipically a lookup or iteration) at the
|
||||
// current path location (not handled here)
|
||||
Path lookupPath = Path::Current(PathCurrent::Lookup);
|
||||
|
||||
// there are various visit methods to iterate/visit DomItems in particular visitTree
|
||||
// which is quite flexible.
|
||||
// They normally use callbacks that can return false to stop the iteration.
|
||||
// Still often the DomKind specific for loop presentated later are clearer and more
|
||||
// convenient
|
||||
{
|
||||
QString s;
|
||||
QTextStream dbg(&s);
|
||||
imports.visitTree(
|
||||
Path(),
|
||||
[&dbg](Path p, const DomItem &el, bool) {
|
||||
dbg << QStringLiteral(u" ").repeated(p.length()) << "*"
|
||||
<< p.last().toString() << " " << domKindToString(el.domKind())
|
||||
<< "(" << el.internalKindStr() << ")\n";
|
||||
// returning false here stops the whole iteration
|
||||
return true;
|
||||
},
|
||||
VisitOption::Default, // we want a recursive visit visiting also the top and
|
||||
// adopted
|
||||
[&dbg](Path p, const DomItem &, bool canonicalChild) {
|
||||
// returning false here skips that branch
|
||||
if (!canonicalChild) {
|
||||
dbg << QStringLiteral(u" ").repeated(p.length()) << "+"
|
||||
<< p.last().toString() << " (adopted, will not recurse)\n";
|
||||
} else if (p && p.headIndex(0) % 2 == 1) {
|
||||
dbg << QStringLiteral(u" ").repeated(p.length()) << "-"
|
||||
<< p.last().toString() << " *recursive visit skipped*\n";
|
||||
return false; // we skip odd entries in lists;
|
||||
} else {
|
||||
dbg << QStringLiteral(u" ").repeated(p.length()) << "+"
|
||||
<< p.last().toString() << "\n";
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[&dbg](Path p, const DomItem &, bool) {
|
||||
dbg << QStringLiteral(u" ").repeated(p.length()) << "="
|
||||
<< p.last().toString() << "\n";
|
||||
return true;
|
||||
});
|
||||
dbg.flush();
|
||||
QCOMPARE(s,
|
||||
QStringLiteral("* List(List)\n"
|
||||
"+\n"
|
||||
" *[0] Object(Import)\n"
|
||||
" +[0]\n"
|
||||
" *.uri Value(ConstantData)\n"
|
||||
" +.uri\n"
|
||||
" =.uri\n"
|
||||
" *.version Object(Version)\n"
|
||||
" +.version\n"
|
||||
" *.majorVersion Value(ConstantData)\n"
|
||||
" +.majorVersion\n"
|
||||
" =.majorVersion\n"
|
||||
" *.minorVersion Value(ConstantData)\n"
|
||||
" +.minorVersion\n"
|
||||
" =.minorVersion\n"
|
||||
" *.isLatest Value(ConstantData)\n"
|
||||
" +.isLatest\n"
|
||||
" =.isLatest\n"
|
||||
" *.isValid Value(ConstantData)\n"
|
||||
" +.isValid\n"
|
||||
" =.isValid\n"
|
||||
" *.stringValue Value(ConstantData)\n"
|
||||
" +.stringValue\n"
|
||||
" =.stringValue\n"
|
||||
" =.version\n"
|
||||
" *.implicit Value(ConstantData)\n"
|
||||
" +.implicit\n"
|
||||
" =.implicit\n"
|
||||
" *.comments Object(RegionComments)\n"
|
||||
" +.comments\n"
|
||||
" =.comments\n"
|
||||
" =[0]\n"
|
||||
" *[1] Object(Import)\n"
|
||||
" -[1] *recursive visit skipped*\n"
|
||||
" *[2] Object(Import)\n"
|
||||
" +[2]\n"
|
||||
" *.uri Value(ConstantData)\n"
|
||||
" +.uri\n"
|
||||
" =.uri\n"
|
||||
" *.version Object(Version)\n"
|
||||
" +.version\n"
|
||||
" *.majorVersion Value(ConstantData)\n"
|
||||
" +.majorVersion\n"
|
||||
" =.majorVersion\n"
|
||||
" *.minorVersion Value(ConstantData)\n"
|
||||
" +.minorVersion\n"
|
||||
" =.minorVersion\n"
|
||||
" *.isLatest Value(ConstantData)\n"
|
||||
" +.isLatest\n"
|
||||
" =.isLatest\n"
|
||||
" *.isValid Value(ConstantData)\n"
|
||||
" +.isValid\n"
|
||||
" =.isValid\n"
|
||||
" *.stringValue Value(ConstantData)\n"
|
||||
" +.stringValue\n"
|
||||
" =.stringValue\n"
|
||||
" =.version\n"
|
||||
" *.implicit Value(ConstantData)\n"
|
||||
" +.implicit\n"
|
||||
" =.implicit\n"
|
||||
" *.comments Object(RegionComments)\n"
|
||||
" +.comments\n"
|
||||
" =.comments\n"
|
||||
" =[2]\n"
|
||||
" *[3] Object(Import)\n"
|
||||
" -[3] *recursive visit skipped*\n"
|
||||
" *[4] Object(Import)\n"
|
||||
" +[4]\n"
|
||||
" *.uri Value(ConstantData)\n"
|
||||
" +.uri\n"
|
||||
" =.uri\n"
|
||||
" *.version Object(Version)\n"
|
||||
" +.version\n"
|
||||
" *.majorVersion Value(ConstantData)\n"
|
||||
" +.majorVersion\n"
|
||||
" =.majorVersion\n"
|
||||
" *.minorVersion Value(ConstantData)\n"
|
||||
" +.minorVersion\n"
|
||||
" =.minorVersion\n"
|
||||
" *.isLatest Value(ConstantData)\n"
|
||||
" +.isLatest\n"
|
||||
" =.isLatest\n"
|
||||
" *.isValid Value(ConstantData)\n"
|
||||
" +.isValid\n"
|
||||
" =.isValid\n"
|
||||
" *.stringValue Value(ConstantData)\n"
|
||||
" +.stringValue\n"
|
||||
" =.stringValue\n"
|
||||
" =.version\n"
|
||||
" *.comments Object(RegionComments)\n"
|
||||
" +.comments\n"
|
||||
" =.comments\n"
|
||||
" =[4]\n"
|
||||
"=\n"));
|
||||
}
|
||||
|
||||
// ### DomKind
|
||||
// any DomItem belongs to 5 basic types
|
||||
|
||||
// 1. Object (a C++ object)
|
||||
QCOMPARE(qmlFile.domKind(), DomKind::Object);
|
||||
// The underlying type of the c++ object can be found with .internalKind()
|
||||
QCOMPARE(qmlFile.internalKind(), DomType::QmlFile);
|
||||
// .initernalKindStr() is a convenience string version of it
|
||||
QCOMPARE(qmlFile.internalKindStr(), u"QmlFile");
|
||||
// the object attributes (fields) can be reached using .field(u"filedName")
|
||||
// normally one should not use a string, but the Fields:: constant
|
||||
DomItem qmlFile2 = tFile.field(Fields::currentItem);
|
||||
// all the available fields can be listed via fields()
|
||||
// qDebug() << "The" << qmlObj.internalKindStr() << "at" << qmlObj.canonicalPath()
|
||||
// << "has the following fields:" << qmlObj.fields();
|
||||
// we can access the underlying C++ object with as<>
|
||||
// if (const QmlFile *qmlFilePtr = qmlFile.as<QmlFile>())
|
||||
// qDebug() << "The QmlFile lives at the address" << qmlFilePtr;
|
||||
//// We can get the shared pointer of the owner type (which for the file is the QmlFile
|
||||
/// itself
|
||||
// if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>())
|
||||
// qDebug() << "QmlFile uses shared pointers as ownership method, the underlying
|
||||
// address "
|
||||
// "is the same"
|
||||
// << qmlFilePtr.get();
|
||||
|
||||
// 2. a (Cbor-) Value, i.e a string, number,...
|
||||
DomItem fPath = qmlFile.field(Fields::canonicalFilePath);
|
||||
QCOMPARE(fPath.domKind(), DomKind::Value);
|
||||
// the Cbor representation of a value can be extracted with .value(), and in this case
|
||||
// we can then call toString
|
||||
// qDebug() << "The filePath DomItem is " << fPath << " and it still 'knows' its path "
|
||||
// << fPath.canonicalPath() << " but can have it also as value:" <<
|
||||
// fPath.value()
|
||||
// << "or even better as string." <<
|
||||
// fPath.value().toString(QLatin1String("*none*"));
|
||||
// a DomItem might have a valid value() even if it is not of type DomKind::Value, indeed
|
||||
// CBor maps and lists are mapped to DomKind::Map and DomKind::List, and can be
|
||||
// traversed thought that but also have a valid value().
|
||||
|
||||
// 3. a list
|
||||
QCOMPARE(imports.domKind(), DomKind::List);
|
||||
// the number of elements can be sound with .indexes() and with .index(n) we access each
|
||||
// element
|
||||
// qDebug() << "We have " << imports.indexes() << " imports, and the first is "
|
||||
// << imports.index(0);
|
||||
// If we want to just loop on the elements .values() is the most convenient way
|
||||
// technically values *always* works even for objects and maps, iterating on the values
|
||||
// for (DomItem import : imports.values()) {
|
||||
// if (const Import *importPtr = import.as<Import>()) {
|
||||
// if (importPtr->implicit)
|
||||
// qDebug() << importPtr->uri << importPtr->version.stringValue();
|
||||
// }
|
||||
//}
|
||||
|
||||
// 4. a map
|
||||
DomItem bindings = qmlObj.field(Fields::bindings);
|
||||
QCOMPARE(bindings.domKind(), DomKind::Map);
|
||||
// The keys of the map can be reached either with .keys() or .sortedKeys(), each element
|
||||
// with .key(k)
|
||||
// qDebug() << "bindings";
|
||||
// for (QString k : bindings.sortedKeys()) {
|
||||
// for (DomItem b : bindings.key(k).values()) {
|
||||
// qDebug() << k << ":" << b;
|
||||
// }
|
||||
//}
|
||||
|
||||
// 5 The empty element
|
||||
DomItem empty;
|
||||
QCOMPARE(empty.domKind(), DomKind::Empty);
|
||||
// The empty element is the only DomItem that casted to bool returns false, so checking
|
||||
// for it can be just an implicit cast to bool
|
||||
QVERIFY(bindings && !empty);
|
||||
// the empty element supports all the previus operations so that one can traverse a non
|
||||
// existing path without checking at every element, but only check the result
|
||||
DomItem nonExisting = qmlFile.field(u"no-existing").key(u"a").index(0);
|
||||
QVERIFY(!nonExisting);
|
||||
|
||||
// the index operator [] can be used instead of .index/.key/.field, it might be slightly
|
||||
// less efficient but works
|
||||
|
||||
// find type
|
||||
// access type
|
||||
|
||||
// ### write out
|
||||
// it is possible to write out a qmlFile (actually also parts of it), which will
|
||||
// automatically reformat it
|
||||
QString reformattedFilePath =
|
||||
QDir(QDir::tempPath())
|
||||
.filePath(QFileInfo(testFilePath).baseName() + QLatin1String(".qml"));
|
||||
DomItem newFile = qmlFile.writeOut(reformattedFilePath);
|
||||
// qDebug() << "reformatted written at " << reformattedFilePath;
|
||||
|
||||
// ## Jumping around
|
||||
// ### Generic Methods
|
||||
// from a DomItem you do no have just deeper in the tree, you can also go up the
|
||||
// hierarch toward the root .container() just goes up one step in the canonicalPath of
|
||||
// the object
|
||||
QCOMPARE(imports, firstImport.container());
|
||||
// .containingObject() goes up to the containing DomKind::Object, skipping over all Maps
|
||||
// and Lists
|
||||
QCOMPARE(qmlFile, firstImport.containingObject());
|
||||
// .owner() returns the shared pointer based "owner" object, qmlFile and
|
||||
// ScriptExpression are owningItems
|
||||
QCOMPARE(qmlFile, bindings.owner());
|
||||
// .top() goes to the top of the tree, i.e the environment (or the universe)
|
||||
QCOMPARE(env, bindings.top());
|
||||
// environment is normally the same as top, but making sure it is a actually a
|
||||
// DomEnvironment
|
||||
QCOMPARE(env, bindings.environment());
|
||||
// the universe is a cache of loaded files which for each file keeps two versions: the
|
||||
// latest and the latest valid it can be reached with .universe(), from the universe you
|
||||
// cannot get back to the environment.
|
||||
QCOMPARE(env.universe().internalKind(), DomType::DomUniverse);
|
||||
|
||||
// ## QML Oriented Methods
|
||||
// The Dom model is not for generic json-like structures, so there are methods tailored
|
||||
// for Qml and its structure The methods can succeed if there is a clearly defined
|
||||
// unique result. sometime there is an obivious, but not necessarily unique choice
|
||||
// (tipically going up the hierarchy), for example given a qml file the obvious choice
|
||||
// for a component is the root component, but the file might contain other inline
|
||||
// components, and for an object with different version exposed (C++ property
|
||||
// versioning) the latest version is the natural choice, but other might be available.
|
||||
// In these case passing GoTo::MostLikely as argument makes the method to this obivious
|
||||
// choice (or possibly even only choice if no other versions/components are actually
|
||||
// defined), instead of refusing any potentially ambiguous situation and returning the
|
||||
// empty element.
|
||||
|
||||
// .fileObject() goes to the object representing the whole file
|
||||
// (from either the external object returned by load or from inside the file)
|
||||
DomItem fileObject = tFile.fileObject();
|
||||
DomItem fileObject2 = imports.fileObject();
|
||||
QCOMPARE(fileObject, fileObject2);
|
||||
QCOMPARE(fileObject.internalKind(), DomType::QmlFile);
|
||||
// .component() goes to the component object.
|
||||
QCOMPARE(qmlObj.component(), qmlFile.component(GoTo::MostLikely));
|
||||
// .pragmas gives access to the pragmas of the current component
|
||||
QCOMPARE(qmlFile.pragmas(), qmlFile.field(Fields::pragmas));
|
||||
|
||||
// QmlObject
|
||||
// QmlObject if the main to represent the type information (methods, bindings,
|
||||
// properties,...) of qml. Please note that QmlObject -> component operation is
|
||||
// potentially lossy, when multiple version are exposed, so we represent a type through
|
||||
// its root object, not through a component.
|
||||
|
||||
// .qmlObject() goes to the current QmlObject
|
||||
QCOMPARE(qmlObj, bindings.qmlObject());
|
||||
|
||||
// Given the centrality of QmlObject several of its attributes have convenience methods
|
||||
// to access them:
|
||||
|
||||
// .children() makes subObjects contained inside a QmlObject accessible
|
||||
// note that it is possible to add objects also by directly binding the children or data
|
||||
// attribute, those children are not listed here, this accesses only those listed inside
|
||||
// the QmlObject
|
||||
QCOMPARE(qmlObj.children(), qmlObj.field(Fields::children));
|
||||
DomItem subObj0 = qmlObj.children().index(0);
|
||||
// .child(<i>) is a shortcut for .children.index(<i>)
|
||||
QCOMPARE(subObj0, qmlObj.child(0));
|
||||
// rootQmlObject goes to the root qmlObject (unless one reaches an empty element)
|
||||
QVERIFY(bool(subObj0));
|
||||
QCOMPARE(subObj0.rootQmlObject(), qmlObj);
|
||||
// .bindings() returns the bindings defined in the current object
|
||||
QCOMPARE(bindings, qmlObj.bindings());
|
||||
DomItem mCompObj = qmlObj.child(0)
|
||||
.child(0)
|
||||
.bindings()
|
||||
.key(u"delegate")
|
||||
.index(0)
|
||||
.field(Fields::value)
|
||||
.child(1);
|
||||
// .methods() gives methods definitions and signals
|
||||
DomItem methods = mCompObj.methods();
|
||||
// qDebug() << "mCompObj methods:";
|
||||
for (QString methodName : methods.sortedKeys()) {
|
||||
for (DomItem method : methods.key(methodName).values()) {
|
||||
if (const MethodInfo *methodPtr = method.as<MethodInfo>()) {
|
||||
QCOMPARE(methodName, methodPtr->name);
|
||||
// qDebug() << " " << methodPtr->name << methodPtr->methodType;
|
||||
}
|
||||
}
|
||||
}
|
||||
// qDebug() << "mCompObj propertyDefs:";
|
||||
// .propertyDefs() returns the properties defined in the current object
|
||||
DomItem pDefs = mCompObj.propertyDefs();
|
||||
for (QString pDefName : pDefs.sortedKeys()) {
|
||||
for (DomItem pDef : pDefs.key(pDefName).values()) {
|
||||
if (const PropertyDefinition *pDefPtr = pDef.as<PropertyDefinition>()) {
|
||||
QCOMPARE(pDefName, pDefPtr->name);
|
||||
// qDebug() << " " << pDefPtr->name << pDefPtr->typeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
// binding and property definitions are about the ones defined in the current object
|
||||
// often one is interested also to the inherited properties.
|
||||
// Here PropertyInfo helps, it list all the definitions and bindings for a given
|
||||
// property in the inheritance order (local definitions, parent definitions, parent
|
||||
// parent definitions,...) .propertyInfos() gives access in the usual way (through a
|
||||
// DomItem)
|
||||
DomItem propertyInfos = mCompObj.propertyInfos();
|
||||
// .propertyInfoWithName(<name>) directly accesses one
|
||||
PropertyInfo pInfo = mCompObj.propertyInfoWithName(QStringLiteral(u"a"));
|
||||
// qDebug() << "bindings" << pInfo.bindings;
|
||||
// .propertyInfoNames() gives the names of the properties
|
||||
QCOMPARE(propertyInfos.keys(), mCompObj.propertyInfoNames());
|
||||
|
||||
// .globalScope() goes to the globa scope object
|
||||
QCOMPARE(qmlObj.globalScope().internalKind(), DomType::GlobalScope);
|
||||
// and scope to the containing scope
|
||||
QCOMPARE(bindings.scope(), qmlObj);
|
||||
}
|
||||
// mutate & edit
|
||||
{
|
||||
// DomItem handles read-only access, but if one wants to change something it cannot be
|
||||
// used. MutableDomItem can be initialized with a DomItem, and provides also the methods
|
||||
// to modify the item. It keeps the OwningItem and the path to the current item.
|
||||
// Mutability can invalidate pointers to non owning items (and thus DomItem).
|
||||
// For this reason one should not modify something that other code can have a DomItem
|
||||
// pointer to, the best practice is to make shared object immutable and never change
|
||||
// them. One should modify only a copy that is used only by a single thread, and do not
|
||||
// shared untils all modifications are done. A MutableItem stays valid (or becomes
|
||||
// Empty), but stays safe to use
|
||||
//
|
||||
// Assuming one guarantees that editing is ok, doing it in practice is just about using
|
||||
// MutableDomItem instead of DomItem
|
||||
// It is possible to simply initialize a mutable item with a DomItem
|
||||
DomItem origFile = tFile.fileObject();
|
||||
MutableDomItem myFile0(origFile);
|
||||
// Normally it is better to have a separate environment. Is possible to avoid re-reading
|
||||
// the files already read by sharing the Universe between two environments.
|
||||
// But normally it is better and just as safe to work on a copy, so that one can be sure
|
||||
// that no DomItem is kept by other code gets invalidated. The .makeCopy creates a deep
|
||||
// copy, and by default (DomItem::CopyOption::EnvConnected) creates an environment which
|
||||
// to takes all non local elements from the current environment (its parent environment)
|
||||
// but replaces the file object with the copy. When finished one can replace the file
|
||||
// object of the parent with the new one using .commitToBase().
|
||||
MutableDomItem myFile = origFile.makeCopy();
|
||||
QVERIFY(myFile.ownerAs<QmlFile>()
|
||||
&& myFile.ownerAs<QmlFile>() != myFile0.ownerAs<QmlFile>());
|
||||
QVERIFY(myFile.environment().ownerAs<DomEnvironment>()
|
||||
&& myFile.environment().ownerAs<DomEnvironment>()
|
||||
!= myFile0.environment().ownerAs<DomEnvironment>());
|
||||
// we can check that the two files are really identical (.item() give back the DomItem
|
||||
// of a MutableDomItem
|
||||
Q_ASSERT(domCompareStrList(origFile, myFile, FieldFilter::compareFilter()).isEmpty());
|
||||
// MutableDomItem has the same methods as DomItem
|
||||
MutableDomItem qmlObj = myFile.qmlObject(GoTo::MostLikely);
|
||||
MutableDomItem qmlObj2 = myFile.field(Fields::components)
|
||||
.key(QString())
|
||||
.index(0)
|
||||
.field(Fields::objects)
|
||||
.index(0);
|
||||
QVERIFY(bool(qmlObj));
|
||||
QCOMPARE(qmlObj, qmlObj2);
|
||||
// qDebug() << "mutable qmlObj has canonicalPath " << qmlObj.canonicalPath();
|
||||
// but it adds methods to add
|
||||
// * new PropertyDefinitions
|
||||
PropertyDefinition b;
|
||||
b.name = QLatin1String("xx");
|
||||
b.typeName = QLatin1String("int");
|
||||
// if we make t true we also have to give a value...
|
||||
MutableDomItem addedPDef = qmlObj.addPropertyDef(b);
|
||||
// qDebug() << "added property definition at:" << addedPDef.pathFromOwner();
|
||||
// * new bindings
|
||||
MutableDomItem addedBinding0 = qmlObj.addBinding(
|
||||
Binding("height",
|
||||
std::shared_ptr<ScriptExpression>(new ScriptExpression(
|
||||
QStringLiteral(u"243"),
|
||||
ScriptExpression::ExpressionType::BindingExpression))));
|
||||
// by default addBinding, addPropertyDef and addMethod have the AddOption::Override
|
||||
// to make it more difficult to create invalid documents, so that only the
|
||||
// following binding remains (where we use the convenience constructor that constucts
|
||||
// the ScriptExpression internally
|
||||
MutableDomItem addedBinding =
|
||||
qmlObj.addBinding(Binding("height", QStringLiteral(u"242")));
|
||||
// qDebug() << "added binding at:" << addedBinding.pathFromOwner();
|
||||
// * new methods
|
||||
MethodInfo mInfo;
|
||||
mInfo.name = QLatin1String("foo2");
|
||||
MethodParameter param;
|
||||
param.name = QLatin1String("x");
|
||||
mInfo.parameters.append(param);
|
||||
mInfo.setCode(QLatin1String("return 4*10+2 - x"));
|
||||
// we can change the added binding
|
||||
addedBinding.setCode(QLatin1String("245"));
|
||||
MutableDomItem addedMethod = qmlObj.addMethod(mInfo);
|
||||
// qDebug() << "added method at:" << addedMethod.pathFromOwner();
|
||||
// * new QmlObjects
|
||||
QmlObject subObj;
|
||||
subObj.setName(QLatin1String("Item"));
|
||||
MutableDomItem addedSubObj = qmlObj.addChild(subObj);
|
||||
// qDebug() << "added subObject at:" << addedMethod.pathFromOwner();
|
||||
// It is possible to modify the content of objects, using the mutableAs method
|
||||
if (PropertyDefinition *addedPDefPtr = addedPDef.mutableAs<PropertyDefinition>()) {
|
||||
addedPDefPtr->isRequired = true;
|
||||
}
|
||||
MutableDomItem firstChild = qmlObj.child(0);
|
||||
// qDebug() << "firstChild:" << firstChild;
|
||||
// It is possible remove objects
|
||||
if (QmlObject *qmlObjPtr = qmlObj.mutableAs<QmlObject>()) {
|
||||
QList<QmlObject> children = qmlObjPtr->children();
|
||||
children.removeAt(0);
|
||||
qmlObjPtr->setChildren(children);
|
||||
}
|
||||
// But as MutableDomItem does not keep the identity, just the same position, the
|
||||
// addedSubObj becomes invalid (and firstChild changes)
|
||||
// qDebug() << "after removal firstChild:" << firstChild;
|
||||
// qDebug() << "addedSubObj becomes invalid:" << addedSubObj;
|
||||
// qDebug() << "But the last object is the added one:"
|
||||
// << qmlObj.child(qmlObj.children().indexes() - 1);
|
||||
|
||||
// now origFile are different
|
||||
Q_ASSERT(!domCompareStrList(origFile, myFile, FieldFilter::compareFilter()).isEmpty());
|
||||
// and we can look at the places where they differ
|
||||
// qDebug().noquote().nospace()
|
||||
// << "Edits introduced the following diffs (ignoring file locations"
|
||||
// << " and thus whitespace/reformatting changes):\n"
|
||||
// << domCompareStrList(origFile, myFile, FieldFilter::noLocationFilter(),
|
||||
// DomCompareStrList::AllDiffs)
|
||||
// .join(QString());
|
||||
|
||||
QString reformattedFilePath =
|
||||
QDir(QDir::tempPath())
|
||||
.filePath(QStringLiteral(u"edited") + QFileInfo(testFilePath).baseName()
|
||||
+ QLatin1String(".qml"));
|
||||
Q_ASSERT(myFile.as<QmlFile>()
|
||||
&& myFile.as<QmlFile>() == myFile.fileObject().as<QmlFile>());
|
||||
MutableDomItem reformattedEditedFile = myFile.writeOut(reformattedFilePath);
|
||||
// the reformatted edited file might be different from the edited file
|
||||
// but the differences are just in file location/formatting
|
||||
Q_ASSERT(domCompareStrList(myFile, reformattedEditedFile,
|
||||
FieldFilter::noLocationFilter())
|
||||
.isEmpty());
|
||||
|
||||
// qDebug() << "The edited file was written at " << reformattedFilePath;
|
||||
QString dumpFilePath = QDir(QDir::tempPath())
|
||||
.filePath(QStringLiteral(u"edited0")
|
||||
+ QFileInfo(testFilePath).baseName()
|
||||
+ QLatin1String(".dump.json"));
|
||||
myFile.dump(dumpFilePath);
|
||||
// qDebug() << "The non reformatted edited file was dumped at " << dumpFilePath;
|
||||
QString reformattedDumpFilePath =
|
||||
QDir(QDir::tempPath())
|
||||
.filePath(QStringLiteral(u"edited") + QFileInfo(testFilePath).baseName()
|
||||
+ QLatin1String(".dump.json"));
|
||||
reformattedEditedFile.dump(reformattedDumpFilePath);
|
||||
// qDebug() << "The edited file was dumped at " << reformattedDumpFilePath;
|
||||
// The top environment still contains the original loaded file
|
||||
Q_ASSERT(origFile.ownerAs<QmlFile>() != reformattedEditedFile.ownerAs<QmlFile>());
|
||||
Q_ASSERT(tFile.fileObject().refreshed().ownerAs<QmlFile>());
|
||||
QCOMPARE(tFile.fileObject().refreshed().ownerAs<QmlFile>(),
|
||||
origFile.ownerAs<QmlFile>());
|
||||
QCOMPARE(tFile.fileObject().ownerAs<QmlFile>(), origFile.ownerAs<QmlFile>());
|
||||
Q_ASSERT(tFile.fileObject().refreshed().ownerAs<QmlFile>()
|
||||
!= reformattedEditedFile.ownerAs<QmlFile>());
|
||||
// we can commit the reformatted file
|
||||
if (!reformattedEditedFile.commitToBase()) {
|
||||
qWarning() << "No reformatted file to commit";
|
||||
}
|
||||
// myFile might not be the same (If and updated check is requested, not the case here)
|
||||
if (myFile.ownerAs<QmlFile>() != reformattedEditedFile.ownerAs<QmlFile>()
|
||||
&& !myFile.commitToBase()) {
|
||||
qWarning() << "Could not commit edited file";
|
||||
}
|
||||
// but refreshing it (looking up its canonical path) we always find the updated file
|
||||
QCOMPARE(myFile.refreshed().ownerAs<QmlFile>(),
|
||||
reformattedEditedFile.ownerAs<QmlFile>());
|
||||
Q_ASSERT(tFile.fileObject().refreshed().ownerAs<QmlFile>()
|
||||
== reformattedEditedFile.ownerAs<QmlFile>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // Dom
|
||||
} // QQmlJS
|
||||
QT_END_NAMESPACE
|
Loading…
Reference in New Issue