30 d->error = Error::NoData;
37 d->error = std::move(other.d_ptr->error);
38 d->mergedMetadata = std::move(other.d_ptr->mergedMetadata);
39 d->mergedShapes = std::move(other.d_ptr->mergedShapes);
40 d->allMetadata = std::move(other.d_ptr->allMetadata);
41 d->allShapes = std::move(other.d_ptr->allShapes);
47 d->error = other.
d_ptr->error;
48 d->mergedMetadata = other.
d_ptr->mergedMetadata;
49 d->mergedShapes = other.
d_ptr->mergedShapes;
50 d->allMetadata = other.
d_ptr->allMetadata;
51 d->allShapes = other.
d_ptr->allShapes;
57 d->error = model.
d_ptr->error;
58 d->mergedMetadata = model.
d_ptr->mergedMetadata;
59 d->mergedShapes = model.
d_ptr->mergedShapes;
60 d->allMetadata = model.
d_ptr->allMetadata;
61 d->allShapes = model.
d_ptr->allShapes;
68 d->error = std::move(model.d_ptr->error);
69 d->mergedMetadata = std::move(model.d_ptr->mergedMetadata);
70 d->mergedShapes = std::move(model.d_ptr->mergedShapes);
71 d->allMetadata = std::move(model.d_ptr->allMetadata);
72 d->allShapes = std::move(model.d_ptr->allShapes);
87 d->error = Error::NoData;
88 d->mergedMetadata = QJsonObject{};
89 d->mergedShapes.clear();
90 d->allMetadata.clear();
105 if (d->error == Error::NoData) {
106 d->error = Error::NoError;
110 d->mergedMetadata = QJsonObject{};
111 d->mergedShapes.clear();
114 const QVersionNumber version = d->smithyVersion(ast);
115 if (version.majorVersion() > 2) {
116 qCWarning(d->lc).noquote() << tr(
"Unknown Smithy version %1").arg(version.toString());
121 const QStringList keys = ast.keys();
122 for (
const QString &key: keys) {
123 const QStringList knownKeys{
124 QStringLiteral(
"smithy"),QStringLiteral(
"metadata"), QStringLiteral(
"shapes") };
125 if (!knownKeys.contains(key)) {
126 qCWarning(d->lc).noquote() << tr(
"Ignoring unknown Smithy AST property %1").arg(key);
131 const QJsonValue metadata = ast.value(QStringLiteral(
"metadata"));
132 if (metadata != QJsonValue::Undefined) {
133 if (!metadata.isObject()) {
134 qCCritical(d->lc).noquote() << tr(
"Smithy AST metadata is not an object");
135 qDebug().noquote() << metadata;
136 if (d->error == Error::NoError) d->error = Error::InvalidMetadata;
139 const QJsonObject
object = metadata.toObject();
140 qCDebug(d->lc).noquote() << tr(
"Processing %n metadata entry(s)",
nullptr,
object.length());
141 for (
auto iter =
object.constBegin(); iter !=
object.constEnd(); ++iter) {
142 d->allMetadata.insert(iter.key(), iter.value());
147 const QJsonValue
shapes = ast.value(QStringLiteral(
"shapes"));
148 if (
shapes != QJsonValue::Undefined) {
150 qCCritical(d->lc).noquote() << tr(
"Smithy AST shapes is not an object");
151 if (d->error == Error::NoError) d->error = Error::InvalidShapes;
154 const QJsonObject
object =
shapes.toObject();
155 qCDebug(d->lc).noquote() << tr(
"Processing %n shape(s)",
nullptr,
object.length());
156 for (
auto iter =
object.constBegin(); iter !=
object.constEnd(); ++iter) {
157 const ShapeId shapeId(iter.key());
159 qCCritical(d->lc).noquote() << tr(
"Failed to parse shape ID %1").arg(iter.key());
160 if (d->error == Error::NoError) d->error = Error::InvalidShapeId;
164 qCCritical(d->lc).noquote() << tr(
"Shape ID %1 has no namespace").arg(iter.key());
165 if (d->error == Error::NoError) d->error = Error::InvalidShapeId;
168 if (!iter.value().isObject()) {
169 qCCritical(d->lc).noquote() << tr(
"Shape %1 is not a JSON object").arg(iter.key());
170 if (d->error == Error::NoError) d->error = Error::InvalidShape;
173 qCDebug(d->lc).noquote() << tr(
"Processing shape %1").arg(shapeId.
toString());
174 const Shape shape{iter.value().toObject(), shapeId};
175 if (!
shape.isValid()) {
176 qCCritical(d->lc).noquote() << tr(
"Failed to process shape %1").arg(iter.key());
177 if (d->error == Error::NoError) d->error = Error::InvalidShape;
180 d->allShapes.insert(iter.key(),
shape);
189 if (d->error != Error::NoError) {
190 qCWarning(d->lc).noquote() << tr(
"Model::finish() called with Model errors present");
194 d->mergedMetadata = ModelPrivate::mergeMetadata(d->allMetadata);
195 if (d->allMetadata.isEmpty() != d->mergedMetadata.isEmpty()) {
196 if (d->error == Error::NoError) d->error = Error::ConflictingMetadata;
205Model::Error Model::error()
const
211bool Model::isValid()
const
214 return (d->error == Error::NoError);
217QJsonObject Model::metadata()
const
220 return d->mergedMetadata;
227 return d->allShapes.value(shapeId);
234 return d->mergedShapes;
236 QHash<ShapeId, Shape>
shapes;
238 for (
auto iter = d->allShapes.constBegin(); iter != d->allShapes.constEnd(); ++iter) {
239 if (iter.value().type() == type) {
240 shapes.insert(iter.key(), iter.value());
263QJsonObject ModelPrivate::mergeMetadata(
const QMultiHash<QString, QJsonValue> &metadata)
265 qCDebug(lc).noquote() << tr(
"Merging %n metedata entry(s)",
nullptr, metadata.size());
267 const QStringList keys = metadata.keys();
268 for (
const QString &key: keys) {
270 const auto values = metadata.values(key);
271 if (values.first().isArray()) {
272 QJsonArray concatenatedArray;
273 for (
const QJsonValue &value: values) {
274 if (!value.isArray()) {
275 qCCritical(lc).noquote() << tr(
"Metadata %1 has conflicting types").arg(key);
276 return QJsonObject{};
278 const QJsonArray thisArray = value.toArray();
279 for (
const QJsonValue &item: thisArray) {
280 concatenatedArray.append(item);
283 merged.insert(key, concatenatedArray);
288 for (
const QJsonValue &value: values) {
289 qDebug() << values.first() << value;
290 if (value != values.first()) {
291 qCDebug(lc).noquote() << tr(
"Metatadata %1 has conflicting values").arg(key);
292 return QJsonObject{};
295 merged.insert(key, values.first());
297 qCDebug(lc).noquote() << tr(
"Merged %n metedata entry(s) to %1",
nullptr, metadata.size())
302QVersionNumber ModelPrivate::smithyVersion(
const QJsonObject &ast)
304 const QString versionString = ast.value(QLatin1String(
"smithy")).toString();
305 qCDebug(lc).noquote() << tr(
"Smithy version string:") << versionString;
306 #if (QT_VERSION < QT_VERSION_CHECK(6, 4, 0))
307 int suffixIndex = -1;
309 qsizetype suffixIndex = -1;
311 const QVersionNumber versionNumber = QVersionNumber::fromString(versionString, &suffixIndex);
312 qCDebug(lc).noquote() << tr(
"Smithy version number:") << versionNumber;
313 if (versionNumber.isNull()) {
314 qCWarning(lc).noquote() << tr(
"Failed to parse Smithy version \"%1\"").arg(versionString);
315 }
else if (suffixIndex < versionString.length()) {
316 qCWarning(lc).noquote() << tr(
"Ignoring Smithy version suffix \"%1\"")
317 .arg(versionString.mid(suffixIndex));
319 return versionNumber;
The ModelPrivate class provides private implementation for Model.
ModelPrivate(Model *const q)
Model * q_ptr
Internal q-pointer.
The Model class provides a Qt representation of a Smithy semantic model.
QHash< ShapeId, Shape > shapes(const Shape::Type &type=Shape::Type::Undefined) const
Shape shape(const ShapeId &shapeId) const
bool insert(const QJsonObject &ast)
Add the logical content of the JSON AST model file given by ast into this semantic model.
~Model()
Destroys this Model object.
Model()
Constructs a new, empty Smithy model.
The ShapeId class provides a Qt representation of a Smithy Shape ID.
bool isValid() const
Returns true if this object represents a valid, non-empty Smithy Shape ID.
QString toString() const
Returns this object as an absolute Smithy Shape ID if this object has a namespace,...
bool hasNameSpace() const
Returns true if this Shape ID has a non-empty namespace, otherwise false otherwise.
The Shape class provides a Qt representation of a Smithy semantic shape.
@ Undefined
The shape is undefined, usually the result of an error condition.
Declares the Model class.
Declares the ModelPrivate class.
#define QTSMITHY_BEGIN_NAMESPACE
Macro for starting the QtSmithy library's top-most namespace (if one is defined).
#define QTSMITHY_END_NAMESPACE
Macro for ending the QtSmithy library's top-most namespace (if one is defined).