aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmltyperegistrar/qqmljsstreamwriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmltyperegistrar/qqmljsstreamwriter.cpp')
-rw-r--r--src/qmltyperegistrar/qqmljsstreamwriter.cpp247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/qmltyperegistrar/qqmljsstreamwriter.cpp b/src/qmltyperegistrar/qqmljsstreamwriter.cpp
new file mode 100644
index 0000000000..32ca4e3b1b
--- /dev/null
+++ b/src/qmltyperegistrar/qqmljsstreamwriter.cpp
@@ -0,0 +1,247 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qqmljsstreamwriter_p.h"
+#include "qanystringviewutils_p.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+// TODO: All of this could be improved by using and re-using one buffer for all the writing.
+// We don't really need to allocate any temporary byte arrays.
+
+static QByteArray enquoteByteArray(QByteArrayView string)
+{
+ const qsizetype length = string.length();
+ QByteArray buffer;
+ buffer.reserve(length + 2);
+ buffer.append(' ');
+ buffer.append(string);
+ buffer.append(' ');
+ buffer.replace('\\', "\\\\").replace('"', "\\\"");
+ buffer[0] = '"';
+ buffer[buffer.length() - 1] = '"';
+ return buffer;
+}
+
+static QByteArray enquoteAnyString(QAnyStringView string)
+{
+ return string.visit([](auto data) {
+ return QAnyStringViewUtils::processAsUtf8(data, [](QByteArrayView view) {
+ return enquoteByteArray(view);
+ });
+ });
+}
+
+QQmlJSStreamWriter::QQmlJSStreamWriter(QByteArray *array)
+ : m_indentDepth(0)
+ , m_pendingLineLength(0)
+ , m_maybeOneline(false)
+ , m_stream(new QBuffer(array))
+{
+ m_stream->open(QIODevice::WriteOnly);
+}
+
+void QQmlJSStreamWriter::writeStartDocument()
+{
+}
+
+void QQmlJSStreamWriter::writeEndDocument()
+{
+}
+
+void QQmlJSStreamWriter::writeLibraryImport(
+ QByteArrayView uri, int majorVersion, int minorVersion, QByteArrayView as)
+{
+ m_stream->write("import ");
+ m_stream->write(uri.data(), uri.length());
+ m_stream->write(" ");
+ m_stream->write(QByteArray::number(majorVersion));
+ m_stream->write(".");
+ m_stream->write(QByteArray::number(minorVersion));
+ if (!as.isEmpty()) {
+ m_stream->write(" as ");
+ m_stream->write(as.data(), as.length());
+ }
+ m_stream->write("\n");
+}
+
+void QQmlJSStreamWriter::writeStartObject(QByteArrayView component)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+ m_stream->write(component.data(), component.length());
+ m_stream->write(" {");
+ ++m_indentDepth;
+ m_maybeOneline = true;
+}
+
+void QQmlJSStreamWriter::writeEndObject()
+{
+ if (m_maybeOneline) {
+ --m_indentDepth;
+ for (int i = 0; i < m_pendingLines.size(); ++i) {
+ m_stream->write(" ");
+ m_stream->write(m_pendingLines.at(i).trimmed());
+ if (i != m_pendingLines.size() - 1)
+ m_stream->write(";");
+ }
+
+ if (!m_pendingLines.isEmpty())
+ m_stream->write(" }\n");
+ else
+ m_stream->write("}\n");
+
+ m_pendingLines.clear();
+ m_pendingLineLength = 0;
+ m_maybeOneline = false;
+ } else {
+ flushPotentialLinesWithNewlines();
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("}\n");
+ }
+}
+
+void QQmlJSStreamWriter::writeScriptBinding(QByteArrayView name, QByteArrayView rhs)
+{
+ QByteArray buffer;
+ buffer.reserve(name.length() + 2 + rhs.length());
+ buffer.append(name);
+ buffer.append(": ");
+ buffer.append(rhs);
+ writePotentialLine(buffer);
+}
+
+void QQmlJSStreamWriter::writeStringBinding(QByteArrayView name, QAnyStringView value)
+{
+ writeScriptBinding(name, enquoteAnyString(value));
+}
+
+void QQmlJSStreamWriter::writeNumberBinding(QByteArrayView name, qint64 value)
+{
+ writeScriptBinding(name, QByteArray::number(value));
+}
+
+void QQmlJSStreamWriter::writeBooleanBinding(QByteArrayView name, bool value)
+{
+ writeScriptBinding(name, value ? "true" : "false");
+}
+
+template<typename String, typename ElementHandler>
+void QQmlJSStreamWriter::doWriteArrayBinding(
+ QByteArrayView name, const QList<String> &elements, ElementHandler &&handler)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+
+ // try to use a single line
+ QByteArray singleLine(name.data(), name.length());
+ singleLine += ": [";
+ for (int i = 0; i < elements.size(); ++i) {
+ QAnyStringViewUtils::processAsUtf8(elements.at(i), [&](QByteArrayView element) {
+ singleLine += handler(element);
+ });
+ if (i != elements.size() - 1)
+ singleLine += ", ";
+ }
+ singleLine += "]\n";
+ if (singleLine.size() + m_indentDepth * 4 < 80) {
+ m_stream->write(singleLine);
+ return;
+ }
+
+ // write multi-line
+ m_stream->write(name.data(), name.length());
+ m_stream->write(": [\n");
+ ++m_indentDepth;
+ for (int i = 0; i < elements.size(); ++i) {
+ writeIndent();
+ QAnyStringViewUtils::processAsUtf8(elements.at(i), [&](QByteArrayView element) {
+ const auto handled = handler(element);
+ m_stream->write(handled.data(), handled.length());
+ });
+ if (i != elements.size() - 1) {
+ m_stream->write(",\n");
+ } else {
+ m_stream->write("\n");
+ }
+ }
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("]\n");
+}
+
+void QQmlJSStreamWriter::writeArrayBinding(QByteArrayView name, const QByteArrayList &elements)
+{
+ doWriteArrayBinding(name, elements, [](QByteArrayView view) { return view; });
+}
+
+void QQmlJSStreamWriter::writeStringListBinding(
+ QByteArrayView name, const QList<QAnyStringView> &elements)
+{
+ doWriteArrayBinding(name, elements, enquoteByteArray);
+}
+
+void QQmlJSStreamWriter::write(QByteArrayView data)
+{
+ flushPotentialLinesWithNewlines();
+ m_stream->write(data.data(), data.length());
+}
+
+void QQmlJSStreamWriter::writeEnumObjectLiteralBinding(
+ QByteArrayView name, const QList<QPair<QAnyStringView, int> > &keyValue)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+ m_stream->write(name.data(), name.length());
+ m_stream->write(": {\n");
+ ++m_indentDepth;
+ for (int i = 0, end = keyValue.size(); i != end; ++i) {
+ writeIndent();
+ const auto &entry = keyValue[i];
+ m_stream->write(enquoteAnyString(entry.first));
+ m_stream->write(": ");
+ m_stream->write(QByteArray::number(entry.second));
+ if (i != end - 1)
+ m_stream->write(",\n");
+ else
+ m_stream->write("\n");
+ }
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("}\n");
+}
+
+void QQmlJSStreamWriter::writeIndent()
+{
+ for (int i = 0; i < m_indentDepth; ++i)
+ m_stream->write(" ");
+}
+
+void QQmlJSStreamWriter::writePotentialLine(const QByteArray &line)
+{
+ m_pendingLines.append(line);
+ m_pendingLineLength += line.size();
+ if (m_pendingLineLength >= 80) {
+ flushPotentialLinesWithNewlines();
+ }
+}
+
+void QQmlJSStreamWriter::flushPotentialLinesWithNewlines()
+{
+ if (m_maybeOneline)
+ m_stream->write("\n");
+ for (const QByteArray &line : std::as_const(m_pendingLines)) {
+ writeIndent();
+ m_stream->write(line);
+ m_stream->write("\n");
+ }
+ m_pendingLines.clear();
+ m_pendingLineLength = 0;
+ m_maybeOneline = false;
+}
+
+QT_END_NAMESPACE