Smithy Qt 0.1.0-pre
Internal development documentation
Loading...
Searching...
No Matches
shape.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2013-2025 Paul Colby <git@colby.id.au>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4/*!
5 * \file
6 * Defines the Shape and ShapePrivate classes.
7 */
8
9#include <qtsmithy/shape.h>
10#include "shape_p.h"
11
12#include <QJsonArray>
13
15
16/*!
17 * \class Shape
18 *
19 * The Shape class provides a Qt representation of a Smithy semantic shape. That is, essentially a
20 * tagged union or variant class, with some specialised conversions for native Qt types.
21 *
22 * \see https://awslabs.github.io/smithy/2.0/spec/shape.html#semantic-shape
23 */
24
25/*!
26 * Constructs a new, empty Smithy shape.
27 */
29{
30 Q_D(Shape);
31 d->error = Error::NoError;
32 d->type = Type::Undefined;
33}
34
35Shape::Shape(const QJsonObject &ast, const ShapeId &id) : d_ptr(new ShapePrivate(this))
36{
37 Q_D(Shape);
38 d->ast = ast;
39 d->error = Error::NoError;
40 d->id = id;
41 d->type = ShapePrivate::getType(ast);
42 if (d->type == Type::Undefined) {
43 d->error = Error::UndefinedShapeType;
44 }
45
46 // Warn on any unsupported properties.
47 const QStringList supportedProperties = ShapePrivate::supportedProperties(d->type);
48 const QStringList keys = ast.keys();
49 for (const QString &key: keys) {
50 if (!supportedProperties.contains(key)) {
51 qCWarning(d->lc).noquote() << tr("Ignoring unsupported Shape property: %1").arg(key);
52 }
53 }
54
55 // Error on any missing required properties.
56 const QStringList requiredProperties = ShapePrivate::requiredProperties(d->type);
57 for (const QString &key: requiredProperties) {
58 if (!keys.contains(key)) {
59 qCritical(d->lc).noquote() << tr("Missing required Shape property: %1").arg(key);
60 d->error = Error::MissingRequiredProperty;
61 }
62 }
63
64 // Validate all present properties.
65 for (auto iter = ast.constBegin(); iter != ast.constEnd(); ++iter) {
66 if (!supportedProperties.contains(iter.key())) {
67 continue;
68 }
69 if (!ShapePrivate::validateProperty(iter.key(), iter.value())) {
70 if (d->error == Error::NoError) {
71 d->error = Error::InvalidPropertyValue;
72 }
73 }
74 }
75}
76
77Shape::Shape(Shape &&other) : d_ptr(new ShapePrivate(this))
78{
79 Q_D(Shape);
80 d->ast = std::move(other.d_ptr->ast);
81 d->error = std::move(other.d_ptr->error);
82 d->id = std::move(other.d_ptr->id);
83 d->type = std::move(other.d_ptr->type);
84}
85
86Shape::Shape(const Shape &other) : d_ptr(new ShapePrivate(this))
87{
88 Q_D(Shape);
89 d->ast = other.d_ptr->ast;
90 d->error = other.d_ptr->error;
91 d->id = other.d_ptr->id;
92 d->type = other.d_ptr->type;
93}
94
95Shape& Shape::operator=(const Shape &shape)
96{
97 Q_D(Shape);
98 d->ast = shape.d_ptr->ast;
99 d->error = shape.d_ptr->error;
100 d->id = shape.d_ptr->id;
101 d->type = shape.d_ptr->type;
102 return *this;
103}
104
105Shape& Shape::operator=(const Shape &&shape)
106{
107 Q_D(Shape);
108 d->ast = std::move(shape.d_ptr->ast);
109 d->error = std::move(shape.d_ptr->error);
110 d->id = std::move(shape.d_ptr->id);
111 d->type = std::move(shape.d_ptr->type);
112 return *this;
113}
114
115/*!
116 * Destroys this Shape object.
117 */
119{
120 delete d_ptr;
121}
122
123Shape::Error Shape::error() const
124{
125 Q_D(const Shape);
126 return d->error;
127}
128
129bool Shape::isValid() const
130{
131 Q_D(const Shape);
132 return ((d->error == Error::NoError) && (d->type != Type::Undefined));
133}
134
135
136ShapeId Shape::id() const
137{
138 Q_D(const Shape);
139 return d->id;
140}
141
142Shape::Type Shape::type() const
143{
144 Q_D(const Shape);
145 return d->type;
146}
147
148Shape::TraitsMap Shape::traits() const
149{
150 Q_D(const Shape);
151 return ShapePrivate::getTraitsMap(d->ast, QStringLiteral("traits"));
152}
153
154Shape::Member Shape::member() const
155{
156 Q_D(const Shape);
157 return ShapePrivate::getMember(d->ast, QStringLiteral("member"));
158}
159
160Shape::Member Shape::key() const
161{
162 Q_D(const Shape);
163 return ShapePrivate::getMember(d->ast, QStringLiteral("key"));
164}
165
166Shape::Member Shape::value() const
167{
168 Q_D(const Shape);
169 return ShapePrivate::getMember(d->ast, QStringLiteral("value"));
170}
171
172Shape::StringMemberMap Shape::members() const
173{
174 Q_D(const Shape);
175 return ShapePrivate::getStrMemberMap(d->ast, QStringLiteral("members"));
176}
177
178QString Shape::version() const
179{
180 Q_D(const Shape);
181 return ShapePrivate::getString(d->ast, QStringLiteral("version"));
182}
183
184Shape::ShapeReferences Shape::operations() const
185{
186 Q_D(const Shape);
187 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral("operations"));
188}
189
190Shape::ShapeReferences Shape::resources() const {
191 Q_D(const Shape);
192 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral("resources"));
193}
194
195Shape::ShapeReferences Shape::errors() const {
196 Q_D(const Shape);
197 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral("errors"));
198}
199
200ShapeIdStringMap Shape::rename() const
201{
202 Q_D(const Shape);
203 return ShapePrivate::getShapeIdStrMap(d->ast, QStringLiteral("rename"));
204}
205
206Shape::StringShapeRefMap Shape::identifiers() const
207{
208 Q_D(const Shape);
209 return ShapePrivate::getStrShapeRefMap(d->ast, QStringLiteral("identifiers"));
210}
211
212Shape::StringShapeRefMap Shape::properties() const
213{
214 Q_D(const Shape);
215 return ShapePrivate::getStrShapeRefMap(d->ast, QStringLiteral("properties"));
216}
217
218Shape::ShapeReference Shape::create() const
219{
220 Q_D(const Shape);
221 return ShapePrivate::getShapeRef(d->ast, QStringLiteral("create"));
222}
223
224Shape::ShapeReference Shape::put() const
225{
226 Q_D(const Shape);
227 return ShapePrivate::getShapeRef(d->ast, QStringLiteral("put"));
228}
229
230Shape::ShapeReference Shape::read() const
231{
232 Q_D(const Shape);
233 return ShapePrivate::getShapeRef(d->ast, QStringLiteral("read"));
234}
235
236Shape::ShapeReference Shape::update() const
237{
238 Q_D(const Shape);
239 return ShapePrivate::getShapeRef(d->ast, QStringLiteral("update"));
240}
241
242Shape::ShapeReference Shape::Delete() const
243{
244 Q_D(const Shape);
245 return ShapePrivate::getShapeRef(d->ast, QStringLiteral("delete"));
246}
247
248Shape::ShapeReference Shape::list() const
249{
250 Q_D(const Shape);
251 return ShapePrivate::getShapeRef(d->ast, QStringLiteral("list"));
252}
253
254Shape::ShapeReferences Shape::collectionOperations() const
255{
256 Q_D(const Shape);
257 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral("collectionOperations"));
258}
259
260Shape::ShapeReference Shape::input() const
261{
262 Q_D(const Shape);
263 return ShapePrivate::getShapeRef(d->ast, QStringLiteral("input"));
264}
265
266Shape::ShapeReference Shape::output() const
267{
268 Q_D(const Shape);
269 return ShapePrivate::getShapeRef(d->ast, QStringLiteral("output"));
270}
271
272Shape::ShapeReferences Shape::mixins() const
273{
274 Q_D(const Shape);
275 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral("mixins"));
276}
277
278QJsonObject Shape::rawAst() const
279{
280 Q_D(const Shape);
281 return d->ast;
282}
283
284#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
285uint qHash(const Shape::ShapeReference &key, uint seed)
286#else
287size_t qHash(const Shape::ShapeReference &key, size_t seed)
288#endif
289{
290 return ::qHash(key.target, seed);
291}
292
293bool operator==(const Shape::ShapeReference &lhs, const Shape::ShapeReference &rhs)
294{
295 return lhs.target == rhs.target;
296}
297
298/*!
299 * \cond internal
300 * \class ShapePrivate
301 *
302 * The ShapePrivate class provides private implementation for Shape.
303 */
304
305/*!
306 * \internal
307 * Constructs a new ShapePrivate object with public implementation \a q.
308 */
310{
311
312}
313
314Shape::Type ShapePrivate::getType(const QJsonObject &ast)
315{
316 const QJsonValue value = ast.value(QLatin1String("type"));
317 if (value.isUndefined()) {
318 qCCritical(lc).noquote() << tr("Shape has no type property");
320 }
321 if (value.type() != QJsonValue::String) {
322 qCCritical(lc).noquote() << tr("Shape type property is not a JSON string:") << value;
324 }
325 return getType(value.toString());
326}
327
328Shape::Type ShapePrivate::getType(const QString &type)
329{
330 // Simple Types
331 if (type == QLatin1String("blob")) return Shape::Type::Blob;
332 if (type == QLatin1String("boolean")) return Shape::Type::Boolean;
333 if (type == QLatin1String("string")) return Shape::Type::String;
334 if (type == QLatin1String("enum")) return Shape::Type::Enum;
335 if (type == QLatin1String("byte")) return Shape::Type::Byte;
336 if (type == QLatin1String("short")) return Shape::Type::Short;
337 if (type == QLatin1String("integer")) return Shape::Type::Integer;
338 if (type == QLatin1String("intEnum")) return Shape::Type::IntEnum;
339 if (type == QLatin1String("long")) return Shape::Type::Long;
340 if (type == QLatin1String("float")) return Shape::Type::Float;
341 if (type == QLatin1String("double")) return Shape::Type::Double;
342 if (type == QLatin1String("bigInteger")) return Shape::Type::BigInteger;
343 if (type == QLatin1String("bigDecimal")) return Shape::Type::BigDecimal;
344 if (type == QLatin1String("timestamp")) return Shape::Type::Timestamp;
345 if (type == QLatin1String("document")) return Shape::Type::Document;
346
347 // Aggregate Types
348 if (type == QLatin1String("list")) return Shape::Type::List;
349 if (type == QLatin1String("set")) return Shape::Type::Set;
350 if (type == QLatin1String("map")) return Shape::Type::Map;
351 if (type == QLatin1String("structure")) return Shape::Type::Structure;
352 if (type == QLatin1String("union")) return Shape::Type::Union;
353
354
355 // Service Types
356 if (type == QLatin1String("service")) return Shape::Type::Service;
357 if (type == QLatin1String("operation")) return Shape::Type::Operation;
358 if (type == QLatin1String("resource")) return Shape::Type::Resource;
359
360 // Special Types
361 if (type == QLatin1String("apply")) return Shape::Type::Apply;
362
363 qCWarning(lc).noquote() << tr("Unknown shape type: %1").arg(type);
365}
366
367Shape::Member ShapePrivate::getMember(const QJsonObject &ast, const QString &name)
368{
369 Shape::Member member;
370 Q_UNUSED(ast);
371 Q_UNUSED(name);
372 Q_UNIMPLEMENTED();
373 return member;
374}
375
376ShapeIdStringMap ShapePrivate::getShapeIdStrMap(const QJsonObject &ast, const QString &name)
377{
378 ShapeIdStringMap shapeIdMap;
379 Q_UNUSED(ast);
380 Q_UNUSED(name);
381 Q_UNIMPLEMENTED();
382 return shapeIdMap;
383}
384
385Shape::ShapeReference ShapePrivate::getShapeRef(const QJsonObject &ast, const QString &name)
386{
387 const auto iter = ast.constFind(name);
388 if (iter == ast.constEnd()) {
389 return Shape::ShapeReference{};
390 }
391 const QJsonObject shapeRefObj = iter->toObject();
392 return Shape::ShapeReference{ shapeRefObj.value(QLatin1String("target")).toString() };
393}
394
395Shape::ShapeReferences ShapePrivate::getShapeRefs(const QJsonObject &ast, const QString &name)
396{
397 const auto iter = ast.constFind(name);
398 if (iter == ast.constEnd()) {
399 return Shape::ShapeReferences{};
400 }
401 const QJsonArray shapeRefsArray = iter->toArray();
402 Shape::ShapeReferences shapeRefs;
403 for (const QJsonValue &shapeRef: shapeRefsArray) {
404 shapeRefs.insert(Shape::ShapeReference{
405 shapeRef.toObject().value(QLatin1String("target")).toString()
406 });
407 }
408 return shapeRefs;
409}
410
411Shape::StringMemberMap ShapePrivate::getStrMemberMap(const QJsonObject &ast, const QString &name)
412{
413 Shape::StringMemberMap memberMap;
414 Q_UNUSED(ast);
415 Q_UNUSED(name);
416 Q_UNIMPLEMENTED();
417 return memberMap;
418}
419
420Shape::StringShapeRefMap ShapePrivate::getStrShapeRefMap(const QJsonObject &ast, const QString &name)
421{
422 Shape::StringShapeRefMap shapeRefMap;
423 Q_UNUSED(ast);
424 Q_UNUSED(name);
425 Q_UNIMPLEMENTED();
426 return shapeRefMap;
427}
428
429Shape::TraitsMap ShapePrivate::getTraitsMap(const QJsonObject &ast, const QString &name)
430{
431 Shape::TraitsMap traitsMap;
432 const QJsonObject traits = ast.value(name).toObject();
433 for (auto iter = traits.constBegin(); iter != traits.constEnd(); ++iter) {
434 traitsMap.insert(iter.key(), iter.value());
435 }
436 return traitsMap;
437}
438
439QString ShapePrivate::getString(const QJsonObject &ast, const QString &name)
440{
441 const auto iter = ast.constFind(name);
442 return (iter == ast.constEnd()) ? QString() : iter->toString();
443}
444
445QStringList ShapePrivate::supportedProperties(const Shape::Type &type)
446{
447 switch (type) {
449 return QStringList{};
450
451 // Simple Types:
455 //case Shape::Type::Enum: <- Same as strucutre and union below.
459 //case Shape::Type::IntEnum: <- Same as strucutre and union below.
467 return QStringList{
468 QLatin1String("type"),
469 QLatin1String("traits"),
470 QLatin1String("mixins"),
471 };
472 break;
473
474 // Aggregate Types
476 //case Shape::Type::Set: <- Set is synonym for List.
477 return QStringList{
478 QLatin1String("type"),
479 QLatin1String("traits"),
480 QLatin1String("member"),
481 QLatin1String("mixins"),
482 };
483 break;
484 case Shape::Type::Map:
485 return QStringList{
486 QLatin1String("type"),
487 QLatin1String("traits"),
488 QLatin1String("key"),
489 QLatin1String("value"),
490 QLatin1String("mixins"),
491 };
492 break;
497 return QStringList{
498 QLatin1String("type"),
499 QLatin1String("traits"),
500 QLatin1String("members"),
501 QLatin1String("mixins"),
502 };
503
504 // Service Types
506 return QStringList{
507 QLatin1String("type"),
508 QLatin1String("traits"),
509 QLatin1String("version"),
510 QLatin1String("operations"),
511 QLatin1String("resources"),
512 QLatin1String("errors"),
513 QLatin1String("rename"),
514 QLatin1String("mixins"),
515 };
517 return QStringList{
518 QLatin1String("type"),
519 QLatin1String("traits"),
520 QLatin1String("input"),
521 QLatin1String("output"),
522 QLatin1String("errors"),
523 QLatin1String("mixins"),
524 };
526 return QStringList{
527 QLatin1String("type"),
528 QLatin1String("traits"),
529 QLatin1String("identifiers"),
530 QLatin1String("properties"),
531 QLatin1String("create"),
532 QLatin1String("put"),
533 QLatin1String("read"),
534 QLatin1String("update"),
535 QLatin1String("delete"),
536 QLatin1String("list"),
537 QLatin1String("operations"),
538 QLatin1String("collectionOperations"),
539 QLatin1String("resources"),
540 QLatin1String("mixins"),
541 };
542
543 // Special Types
545 return QStringList{
546 QLatin1String("type"),
547 QLatin1String("traits"),
548 };
549 break;
550 }
551 qCWarning(lc).noquote() << tr("Unknown shape type: 0x%1").arg((int)type, 0, 16);
552 return QStringList{};
553}
554
555QStringList ShapePrivate::requiredProperties(const Shape::Type &type)
556{
557 switch (type) {
559 //case Shape::Type::Set: <- Set is synonym for List.
560 return QStringList{
561 QLatin1String("type"),
562 QLatin1String("member"),
563 };
564 break;
565
566 case Shape::Type::Map:
567 return QStringList{
568 QLatin1String("type"),
569 QLatin1String("key"),
570 QLatin1String("value"),
571 };
572 break;
573
577 return QStringList{
578 QLatin1String("type"),
579 QLatin1String("members"),
580 };
581
583 return QStringList{
584 QLatin1String("type"),
585 QLatin1String("version"),
586 };
587
589 return QStringList{
590 QLatin1String("type"),
591 QLatin1String("traits"),
592 };
593 break;
594
595 default:
596 return QStringList{
597 QLatin1String("type"),
598 };
599 }
600}
601
602bool ShapePrivate::validateIdentifier(const QString &id)
603{
604 // Lazily relying on the fact that ShapeId will validate the idenitifer regex pattern for now.
605 const ShapeId shapeId(id);
606 return ((shapeId.isValid()) && (!shapeId.hasNameSpace()) && (!shapeId.hasMemberName()));
607}
608
609bool ShapePrivate::validateProperty(const QString &name, const QJsonValue &value)
610{
611 // Type string
612 if (name == QLatin1String("type")) {
613 if (!value.isString()) {
614 qCCritical(lc).noquote() << tr("%1 property is not a JSON string").arg(name);
615 return false;
616 }
617 return (getType(value.toString()) != Shape::Type::Undefined);
618 }
619
620 // TraitsMap
621 else if (name == QLatin1String("traits")) {
622 if (!value.isObject()) {
623 qCCritical(lc).noquote() << tr("%1 property is not a JSON object").arg(name);
624 return false;
625 }
626 const QJsonObject traits = value.toObject();
627 for (auto iter = traits.constBegin(); iter != traits.constEnd(); ++iter) {
628 const ShapeId id(iter.key());
629 if (!id.isValid()) {
630 qCCritical(lc).noquote() << tr("%1 property has trait with invalid shape ID %2")
631 .arg(name, iter.key());
632 return false;
633 }
634 if (id.isRelativeShapeId()) {
635 qCCritical(lc).noquote() << tr("%1 property has trait with relative shape ID %2")
636 .arg(name, iter.key());
637 return false;
638 }
639 // It doesn't matter (at this point) what type iter->value() is.
640 }
641 }
642
643 // Member (aka ShapeReference plus optional TraitsMap)
644 else if ((name == QLatin1String("member")) ||
645 (name == QLatin1String("key")) ||
646 (name == QLatin1String("value")))
647 {
648 if (!value.isObject()) {
649 qCCritical(lc).noquote() << tr("%1 property is not a JSON object").arg(name);
650 return false;
651 }
652 if (!validateProperty(QStringLiteral("ShapeReference"), value)) {
653 qCCritical(lc).noquote() << tr("%1 property is not valid ShapeReference").arg(name);
654 return false;
655 }
656 const QJsonObject member = value.toObject();
657 const auto traits = member.constFind(QLatin1String("traits")); // Optional.
658 if ((traits != member.constEnd()) && (!validateProperty(traits.key(), traits.value()))) {
659 qCCritical(lc).noquote() << tr("%1 property has invalid traits property").arg(name);
660 return false;
661 }
662 }
663
664 // Members (ie Set of Member instances)
665 else if (name == QLatin1String("members")) {
666 if (!value.isObject()) {
667 qCCritical(lc).noquote() << tr("%1 property is not a JSON object").arg(name);
668 return false;
669 }
670 QStringList names;
671 const QJsonObject members = value.toObject();
672 for (auto iter = members.constBegin(); iter != members.constEnd(); ++iter) {
673 if (!validateIdentifier(iter.key())) {
674 qCCritical(lc).noquote() << tr("%1 property has invalid member name %2")
675 .arg(name, iter.key());
676 return false;
677 }
678 if (names.contains(iter.key().toLower())) {
679 qCCritical(lc).noquote() << tr("%1 property has non-unique member name %2")
680 .arg(name, iter.key().toLower());
681 return false;
682 }
683 names.append(iter.key().toLower());
684 if (!validateProperty(QLatin1String("member"), iter.value())) {
685 qCCritical(lc).noquote() << tr("%1 property has invalid value for %2 property")
686 .arg(name, iter.key());
687 return false;
688 }
689 }
690 }
691
692 // Plain string
693 else if (name == QLatin1String("version")) {
694 if (!value.isString()) {
695 qCCritical(lc).noquote() << tr("%1 property is not a JSON string").arg(name);
696 return false;
697 }
698 // No further validation required; the string is free-form.
699 }
700
701 // ShapeReferences
702 else if ((name == QLatin1String("operations")) ||
703 (name == QLatin1String("collectionOperations")) ||
704 (name == QLatin1String("resources")) ||
705 (name == QLatin1String("errors")) ||
706 (name == QLatin1String("mixins"))) {
707 if (!value.isArray()) {
708 qCCritical(lc).noquote() << tr("%1 property is not a JSON array").arg(name);
709 return false;
710 }
711 const QJsonArray shapeRefs = value.toArray();
712 for (const QJsonValue &shapeRef: shapeRefs) {
713 if (!validateProperty(QLatin1String("ShapeReference"), shapeRef)) {
714 qCCritical(lc).noquote() << tr("%1 property has invalid entry").arg(name);
715 }
716 }
717 }
718
719 // ShapeIdStringMap
720 else if (name == QLatin1String("rename")) {
721 if (!value.isObject()) {
722 qCCritical(lc).noquote() << tr("%1 property is not a JSON object").arg(name);
723 return false;
724 }
725 const QJsonObject rename = value.toObject();
726 for (auto iter = rename.constBegin(); iter != rename.constEnd(); ++iter) {
727 const ShapeId shapeId(iter.key());
728 if (!shapeId.isValid()) {
729 qCCritical(lc).noquote() << tr("%1 property has invalid shape ID %2")
730 .arg(name, iter.key());
731 return false;
732 }
733 if (!iter.value().isString()) {
734 qCCritical(lc).noquote() << tr("%1 property has shape ID %2 with invalid value")
735 .arg(name, iter.key());
736 return false;
737 }
738 const QString indentifier = iter.value().toString();
739 if (validateIdentifier(indentifier)) {
740 qCCritical(lc).noquote() << tr("%1 property has shape ID %2 with invalid identifier %3")
741 .arg(name, iter.key(), indentifier);
742 return false;
743 }
744 }
745 }
746
747 // ShapeReference
748 else if ((name == QLatin1String("ShapeReference")) ||
749 (name == QLatin1String("create")) ||
750 (name == QLatin1String("put")) ||
751 (name == QLatin1String("read")) ||
752 (name == QLatin1String("update")) ||
753 (name == QLatin1String("delete")) ||
754 (name == QLatin1String("list")) ||
755 (name == QLatin1String("input")) ||
756 (name == QLatin1String("output"))) {
757 if (!value.isObject()) {
758 qCCritical(lc).noquote() << tr("%1 property is not a JSON object").arg(name);
759 return false;
760 }
761 const QJsonObject shapeRef = value.toObject();
762 const auto target = shapeRef.constFind(QLatin1String("target")); // Required.
763 if (target == shapeRef.constEnd()) {
764 qCCritical(lc).noquote() << tr("%1 property has no target property").arg(name);
765 return false;
766 }
767 if (!target.value().isString()) {
768 qCCritical(lc).noquote() << tr("%1 property has target value that not a JSON string")
769 .arg(name);
770 return false;
771 }
772 const QString shapeIdString = target.value().toString();
773 const ShapeId shapeId(shapeIdString);
774 if (!shapeId.isValid()) {
775 qCCritical(lc).noquote() << tr("%1 property has target with invalid shape ID %2")
776 .arg(name, shapeIdString);
777 return false;
778 }
779 if (shapeId.isRelativeShapeId()) {
780 qCCritical(lc).noquote() << tr("%1 property has target with relative shape ID %2")
781 .arg(name, shapeIdString);
782 return false;
783 }
784 }
785
786 // StringShapeRefMap
787 else if ((name == QLatin1String("identifiers")) ||
788 (name == QLatin1String("properties"))) {
789 if (!value.isObject()) {
790 qCCritical(lc).noquote() << tr("%1 property is not a JSON object").arg(name);
791 return false;
792 }
793 const QJsonObject identifiers = value.toObject();
794 for (auto iter = identifiers.constBegin(); iter != identifiers.constEnd(); ++iter) {
795 if (!validateIdentifier(iter.key())) {
796 qCCritical(lc).noquote() << tr("%1 property has invalid member name %2")
797 .arg(name, iter.key());
798 return false;
799 }
800 if (!validateProperty(QLatin1String("ShapeReference"), iter.value())) {
801 qCCritical(lc).noquote() << tr("%1 property has invalid value for %2 property")
802 .arg(name, iter.key());
803 return false;
804 }
805 }
806 }
807
808 else {
809 qCWarning(lc).noquote() << tr("Validation of %1 property not yet implemented").arg(name);
810 return false;
811 }
812 return true;
813}
814
815/// \endcond
816
The ShapeId class provides a Qt representation of a Smithy Shape ID.
Definition shapeid.h:29
The ShapePrivate class provides private implementation for Shape.
Definition shape_p.h:20
Shape * q_ptr
Internal q-pointer.
Definition shape_p.h:45
ShapePrivate(Shape *const q)
Definition shape.cpp:309
The Shape class provides a Qt representation of a Smithy semantic shape.
Definition shape.h:25
ShapePrivate * d_ptr
Definition shape.h:148
Type
Definition shape.h:37
@ IntEnum
An integer with a fixed set of values.
Definition shape.h:48
@ Document
Open content that functions as a kind of "any" type.
Definition shape.h:55
@ Float
Single precision IEEE-754 floating point number.
Definition shape.h:50
@ String
UTF-8 encoded string.
Definition shape.h:43
@ Boolean
Boolean value type.
Definition shape.h:42
@ Operation
Represents the input, output, and errors of an API operation.
Definition shape.h:67
@ Short
16-bit signed integer ranging from -32,768 to 32,767 (inclusive).
Definition shape.h:46
@ Map
Map data structure that maps string keys to homogeneous values.
Definition shape.h:60
@ List
Ordered collection of homogeneous values.
Definition shape.h:58
@ Set
Deprecated; use a list with the uniqueItems trait instead.
Definition shape.h:59
@ Long
64-bit signed integer ranging from -2^63 to (2^63)-1 (inclusive).
Definition shape.h:49
@ Apply
Traits to be applied to shapes outside of their definition.
Definition shape.h:71
@ Integer
32-bit signed integer ranging from -2^31 to (2^31)-1 (inclusive).
Definition shape.h:47
@ Byte
8-bit signed integer ranging from -128 to 127 (inclusive).
Definition shape.h:45
@ Timestamp
An instant in time with no UTC offset or timezone.
Definition shape.h:54
@ Resource
Entity with an identity that has a set of operations.
Definition shape.h:68
@ Service
Entry point of an API that aggregates resources and operations together.
Definition shape.h:66
@ Enum
A string with a fixed set of values.
Definition shape.h:44
@ BigInteger
Arbitrarily large signed integer.
Definition shape.h:52
@ Double
Double precision IEEE-754 floating point number.
Definition shape.h:51
@ Structure
Fixed set of named heterogeneous members.
Definition shape.h:61
@ Blob
Uninterpreted binary data.
Definition shape.h:41
@ BigDecimal
Arbitrary precision signed decimal number.
Definition shape.h:53
@ Undefined
The shape is undefined, usually the result of an error condition.
Definition shape.h:38
~Shape()
Destroys this Shape object.
Definition shape.cpp:118
Shape()
Constructs a new, empty Smithy shape.
Definition shape.cpp:28
#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).
Declares the Shape class.
Declares the ShapePrivate class.