1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qqmljsstreamwriter_p.h"
5#include "qanystringviewutils_p.h"
6
7#include <QtCore/QBuffer>
8#include <QtCore/QStringList>
9
10QT_BEGIN_NAMESPACE
11
12// TODO: All of this could be improved by using and re-using one buffer for all the writing.
13// We don't really need to allocate any temporary byte arrays.
14
15static QByteArray enquoteByteArray(QByteArrayView string)
16{
17 const qsizetype length = string.length();
18 QByteArray buffer;
19 buffer.reserve(asize: length + 2);
20 buffer.append(c: ' ');
21 buffer.append(a: string);
22 buffer.append(c: ' ');
23 buffer.replace(before: '\\', after: "\\\\").replace(before: '"', after: "\\\"");
24 buffer[0] = '"';
25 buffer[buffer.length() - 1] = '"';
26 return buffer;
27}
28
29static QByteArray enquoteAnyString(QAnyStringView string)
30{
31 return string.visit(v: [](auto data) {
32 return QAnyStringViewUtils::processAsUtf8(data, [](QByteArrayView view) {
33 return enquoteByteArray(string: view);
34 });
35 });
36}
37
38QQmlJSStreamWriter::QQmlJSStreamWriter(QByteArray *array)
39 : m_indentDepth(0)
40 , m_pendingLineLength(0)
41 , m_maybeOneline(false)
42 , m_stream(new QBuffer(array))
43{
44 m_stream->open(mode: QIODevice::WriteOnly);
45}
46
47void QQmlJSStreamWriter::writeStartDocument()
48{
49}
50
51void QQmlJSStreamWriter::writeEndDocument()
52{
53}
54
55void QQmlJSStreamWriter::writeLibraryImport(
56 QByteArrayView uri, int majorVersion, int minorVersion, QByteArrayView as)
57{
58 m_stream->write(data: "import ");
59 m_stream->write(data: uri.data(), len: uri.length());
60 m_stream->write(data: " ");
61 m_stream->write(data: QByteArray::number(majorVersion));
62 m_stream->write(data: ".");
63 m_stream->write(data: QByteArray::number(minorVersion));
64 if (!as.isEmpty()) {
65 m_stream->write(data: " as ");
66 m_stream->write(data: as.data(), len: as.length());
67 }
68 m_stream->write(data: "\n");
69}
70
71void QQmlJSStreamWriter::writeStartObject(QByteArrayView component)
72{
73 flushPotentialLinesWithNewlines();
74 writeIndent();
75 m_stream->write(data: component.data(), len: component.length());
76 m_stream->write(data: " {");
77 ++m_indentDepth;
78 m_maybeOneline = true;
79}
80
81void QQmlJSStreamWriter::writeEndObject()
82{
83 if (m_maybeOneline) {
84 --m_indentDepth;
85 for (int i = 0; i < m_pendingLines.size(); ++i) {
86 m_stream->write(data: " ");
87 m_stream->write(data: m_pendingLines.at(i).trimmed());
88 if (i != m_pendingLines.size() - 1)
89 m_stream->write(data: ";");
90 }
91
92 if (!m_pendingLines.isEmpty())
93 m_stream->write(data: " }\n");
94 else
95 m_stream->write(data: "}\n");
96
97 m_pendingLines.clear();
98 m_pendingLineLength = 0;
99 m_maybeOneline = false;
100 } else {
101 flushPotentialLinesWithNewlines();
102 --m_indentDepth;
103 writeIndent();
104 m_stream->write(data: "}\n");
105 }
106}
107
108void QQmlJSStreamWriter::writeScriptBinding(QByteArrayView name, QByteArrayView rhs)
109{
110 QByteArray buffer;
111 buffer.reserve(asize: name.length() + 2 + rhs.length());
112 buffer.append(a: name);
113 buffer.append(s: ": ");
114 buffer.append(a: rhs);
115 writePotentialLine(line: buffer);
116}
117
118void QQmlJSStreamWriter::writeStringBinding(QByteArrayView name, QAnyStringView value)
119{
120 writeScriptBinding(name, rhs: enquoteAnyString(string: value));
121}
122
123void QQmlJSStreamWriter::writeNumberBinding(QByteArrayView name, qint64 value)
124{
125 writeScriptBinding(name, rhs: QByteArray::number(value));
126}
127
128void QQmlJSStreamWriter::writeBooleanBinding(QByteArrayView name, bool value)
129{
130 writeScriptBinding(name, rhs: value ? "true" : "false");
131}
132
133template<typename String, typename ElementHandler>
134void QQmlJSStreamWriter::doWriteArrayBinding(
135 QByteArrayView name, const QList<String> &elements, ElementHandler &&handler)
136{
137 flushPotentialLinesWithNewlines();
138 writeIndent();
139
140 // try to use a single line
141 QByteArray singleLine(name.data(), name.length());
142 singleLine += ": [";
143 for (int i = 0; i < elements.size(); ++i) {
144 QAnyStringViewUtils::processAsUtf8(elements.at(i), [&](QByteArrayView element) {
145 singleLine += handler(element);
146 });
147 if (i != elements.size() - 1)
148 singleLine += ", ";
149 }
150 singleLine += "]\n";
151 if (singleLine.size() + m_indentDepth * 4 < 80) {
152 m_stream->write(data: singleLine);
153 return;
154 }
155
156 // write multi-line
157 m_stream->write(data: name.data(), len: name.length());
158 m_stream->write(data: ": [\n");
159 ++m_indentDepth;
160 for (int i = 0; i < elements.size(); ++i) {
161 writeIndent();
162 QAnyStringViewUtils::processAsUtf8(elements.at(i), [&](QByteArrayView element) {
163 const auto handled = handler(element);
164 m_stream->write(handled.data(), handled.length());
165 });
166 if (i != elements.size() - 1) {
167 m_stream->write(data: ",\n");
168 } else {
169 m_stream->write(data: "\n");
170 }
171 }
172 --m_indentDepth;
173 writeIndent();
174 m_stream->write(data: "]\n");
175}
176
177void QQmlJSStreamWriter::writeArrayBinding(QByteArrayView name, const QByteArrayList &elements)
178{
179 doWriteArrayBinding(name, elements, handler: [](QByteArrayView view) { return view; });
180}
181
182void QQmlJSStreamWriter::writeStringListBinding(
183 QByteArrayView name, const QList<QAnyStringView> &elements)
184{
185 doWriteArrayBinding(name, elements, handler&: enquoteByteArray);
186}
187
188void QQmlJSStreamWriter::write(QByteArrayView data)
189{
190 flushPotentialLinesWithNewlines();
191 m_stream->write(data: data.data(), len: data.length());
192}
193
194void QQmlJSStreamWriter::writeEnumObjectLiteralBinding(
195 QByteArrayView name, const QList<QPair<QAnyStringView, int> > &keyValue)
196{
197 flushPotentialLinesWithNewlines();
198 writeIndent();
199 m_stream->write(data: name.data(), len: name.length());
200 m_stream->write(data: ": {\n");
201 ++m_indentDepth;
202 for (int i = 0, end = keyValue.size(); i != end; ++i) {
203 writeIndent();
204 const auto &entry = keyValue[i];
205 m_stream->write(data: enquoteAnyString(string: entry.first));
206 m_stream->write(data: ": ");
207 m_stream->write(data: QByteArray::number(entry.second));
208 if (i != end - 1)
209 m_stream->write(data: ",\n");
210 else
211 m_stream->write(data: "\n");
212 }
213 --m_indentDepth;
214 writeIndent();
215 m_stream->write(data: "}\n");
216}
217
218void QQmlJSStreamWriter::writeIndent()
219{
220 for (int i = 0; i < m_indentDepth; ++i)
221 m_stream->write(data: " ");
222}
223
224void QQmlJSStreamWriter::writePotentialLine(const QByteArray &line)
225{
226 m_pendingLines.append(t: line);
227 m_pendingLineLength += line.size();
228 if (m_pendingLineLength >= 80) {
229 flushPotentialLinesWithNewlines();
230 }
231}
232
233void QQmlJSStreamWriter::flushPotentialLinesWithNewlines()
234{
235 if (m_maybeOneline)
236 m_stream->write(data: "\n");
237 for (const QByteArray &line : std::as_const(t&: m_pendingLines)) {
238 writeIndent();
239 m_stream->write(data: line);
240 m_stream->write(data: "\n");
241 }
242 m_pendingLines.clear();
243 m_pendingLineLength = 0;
244 m_maybeOneline = false;
245}
246
247QT_END_NAMESPACE
248

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/qmltyperegistrar/qqmljsstreamwriter.cpp