31 d->error = Error::NoError;
39 d->error = Error::NoError;
41 d->type = ShapePrivate::getType(ast);
43 d->error = Error::UndefinedShapeType;
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);
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;
65 for (
auto iter = ast.constBegin(); iter != ast.constEnd(); ++iter) {
66 if (!supportedProperties.contains(iter.key())) {
69 if (!ShapePrivate::validateProperty(iter.key(), iter.value())) {
70 if (d->error == Error::NoError) {
71 d->error = Error::InvalidPropertyValue;
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);
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;
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;
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);
123Shape::Error Shape::error()
const
129bool Shape::isValid()
const
148Shape::TraitsMap Shape::traits()
const
151 return ShapePrivate::getTraitsMap(d->ast, QStringLiteral(
"traits"));
157 return ShapePrivate::getMember(d->ast, QStringLiteral(
"member"));
163 return ShapePrivate::getMember(d->ast, QStringLiteral(
"key"));
169 return ShapePrivate::getMember(d->ast, QStringLiteral(
"value"));
172Shape::StringMemberMap Shape::members()
const
175 return ShapePrivate::getStrMemberMap(d->ast, QStringLiteral(
"members"));
178QString Shape::version()
const
181 return ShapePrivate::getString(d->ast, QStringLiteral(
"version"));
184Shape::ShapeReferences Shape::operations()
const
187 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral(
"operations"));
190Shape::ShapeReferences Shape::resources()
const {
192 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral(
"resources"));
195Shape::ShapeReferences Shape::errors()
const {
197 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral(
"errors"));
200ShapeIdStringMap Shape::rename()
const
203 return ShapePrivate::getShapeIdStrMap(d->ast, QStringLiteral(
"rename"));
206Shape::StringShapeRefMap Shape::identifiers()
const
209 return ShapePrivate::getStrShapeRefMap(d->ast, QStringLiteral(
"identifiers"));
212Shape::StringShapeRefMap Shape::properties()
const
215 return ShapePrivate::getStrShapeRefMap(d->ast, QStringLiteral(
"properties"));
221 return ShapePrivate::getShapeRef(d->ast, QStringLiteral(
"create"));
227 return ShapePrivate::getShapeRef(d->ast, QStringLiteral(
"put"));
233 return ShapePrivate::getShapeRef(d->ast, QStringLiteral(
"read"));
239 return ShapePrivate::getShapeRef(d->ast, QStringLiteral(
"update"));
245 return ShapePrivate::getShapeRef(d->ast, QStringLiteral(
"delete"));
251 return ShapePrivate::getShapeRef(d->ast, QStringLiteral(
"list"));
254Shape::ShapeReferences Shape::collectionOperations()
const
257 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral(
"collectionOperations"));
263 return ShapePrivate::getShapeRef(d->ast, QStringLiteral(
"input"));
269 return ShapePrivate::getShapeRef(d->ast, QStringLiteral(
"output"));
272Shape::ShapeReferences Shape::mixins()
const
275 return ShapePrivate::getShapeRefs(d->ast, QStringLiteral(
"mixins"));
278QJsonObject Shape::rawAst()
const
284#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
290 return ::qHash(key.target, seed);
295 return lhs.target == rhs.target;
314Shape::Type ShapePrivate::getType(
const QJsonObject &ast)
316 const QJsonValue value = ast.value(QLatin1String(
"type"));
317 if (value.isUndefined()) {
318 qCCritical(lc).noquote() << tr(
"Shape has no type property");
321 if (value.type() != QJsonValue::String) {
322 qCCritical(lc).noquote() << tr(
"Shape type property is not a JSON string:") << value;
325 return getType(value.toString());
328Shape::Type ShapePrivate::getType(
const QString &type)
363 qCWarning(lc).noquote() << tr(
"Unknown shape type: %1").arg(type);
367Shape::Member ShapePrivate::getMember(
const QJsonObject &ast,
const QString &name)
369 Shape::Member member;
376ShapeIdStringMap ShapePrivate::getShapeIdStrMap(
const QJsonObject &ast,
const QString &name)
378 ShapeIdStringMap shapeIdMap;
387 const auto iter = ast.constFind(name);
388 if (iter == ast.constEnd()) {
389 return Shape::ShapeReference{};
391 const QJsonObject shapeRefObj = iter->toObject();
392 return Shape::ShapeReference{ shapeRefObj.value(QLatin1String(
"target")).toString() };
395Shape::ShapeReferences ShapePrivate::getShapeRefs(
const QJsonObject &ast,
const QString &name)
397 const auto iter = ast.constFind(name);
398 if (iter == ast.constEnd()) {
399 return Shape::ShapeReferences{};
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()
411Shape::StringMemberMap ShapePrivate::getStrMemberMap(
const QJsonObject &ast,
const QString &name)
413 Shape::StringMemberMap memberMap;
420Shape::StringShapeRefMap ShapePrivate::getStrShapeRefMap(
const QJsonObject &ast,
const QString &name)
422 Shape::StringShapeRefMap shapeRefMap;
429Shape::TraitsMap ShapePrivate::getTraitsMap(
const QJsonObject &ast,
const QString &name)
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());
439QString ShapePrivate::getString(
const QJsonObject &ast,
const QString &name)
441 const auto iter = ast.constFind(name);
442 return (iter == ast.constEnd()) ? QString() : iter->toString();
445QStringList ShapePrivate::supportedProperties(
const Shape::Type &type)
449 return QStringList{};
468 QLatin1String(
"type"),
469 QLatin1String(
"traits"),
470 QLatin1String(
"mixins"),
478 QLatin1String(
"type"),
479 QLatin1String(
"traits"),
480 QLatin1String(
"member"),
481 QLatin1String(
"mixins"),
486 QLatin1String(
"type"),
487 QLatin1String(
"traits"),
488 QLatin1String(
"key"),
489 QLatin1String(
"value"),
490 QLatin1String(
"mixins"),
498 QLatin1String(
"type"),
499 QLatin1String(
"traits"),
500 QLatin1String(
"members"),
501 QLatin1String(
"mixins"),
507 QLatin1String(
"type"),
508 QLatin1String(
"traits"),
509 QLatin1String(
"version"),
510 QLatin1String(
"operations"),
511 QLatin1String(
"resources"),
512 QLatin1String(
"errors"),
513 QLatin1String(
"rename"),
514 QLatin1String(
"mixins"),
518 QLatin1String(
"type"),
519 QLatin1String(
"traits"),
520 QLatin1String(
"input"),
521 QLatin1String(
"output"),
522 QLatin1String(
"errors"),
523 QLatin1String(
"mixins"),
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"),
546 QLatin1String(
"type"),
547 QLatin1String(
"traits"),
551 qCWarning(lc).noquote() << tr(
"Unknown shape type: 0x%1").arg((
int)type, 0, 16);
552 return QStringList{};
555QStringList ShapePrivate::requiredProperties(
const Shape::Type &type)
561 QLatin1String(
"type"),
562 QLatin1String(
"member"),
568 QLatin1String(
"type"),
569 QLatin1String(
"key"),
570 QLatin1String(
"value"),
578 QLatin1String(
"type"),
579 QLatin1String(
"members"),
584 QLatin1String(
"type"),
585 QLatin1String(
"version"),
590 QLatin1String(
"type"),
591 QLatin1String(
"traits"),
597 QLatin1String(
"type"),
602bool ShapePrivate::validateIdentifier(
const QString &
id)
605 const ShapeId shapeId(
id);
606 return ((shapeId.isValid()) && (!shapeId.hasNameSpace()) && (!shapeId.hasMemberName()));
609bool ShapePrivate::validateProperty(
const QString &name,
const QJsonValue &value)
612 if (name == QLatin1String(
"type")) {
613 if (!value.isString()) {
614 qCCritical(lc).noquote() << tr(
"%1 property is not a JSON string").arg(name);
621 else if (name == QLatin1String(
"traits")) {
622 if (!value.isObject()) {
623 qCCritical(lc).noquote() << tr(
"%1 property is not a JSON object").arg(name);
626 const QJsonObject traits = value.toObject();
627 for (
auto iter = traits.constBegin(); iter != traits.constEnd(); ++iter) {
628 const ShapeId id(iter.key());
630 qCCritical(lc).noquote() << tr(
"%1 property has trait with invalid shape ID %2")
631 .arg(name, iter.key());
634 if (
id.isRelativeShapeId()) {
635 qCCritical(lc).noquote() << tr(
"%1 property has trait with relative shape ID %2")
636 .arg(name, iter.key());
644 else if ((name == QLatin1String(
"member")) ||
645 (name == QLatin1String(
"key")) ||
646 (name == QLatin1String(
"value")))
648 if (!value.isObject()) {
649 qCCritical(lc).noquote() << tr(
"%1 property is not a JSON object").arg(name);
652 if (!validateProperty(QStringLiteral(
"ShapeReference"), value)) {
653 qCCritical(lc).noquote() << tr(
"%1 property is not valid ShapeReference").arg(name);
656 const QJsonObject member = value.toObject();
657 const auto traits = member.constFind(QLatin1String(
"traits"));
658 if ((traits != member.constEnd()) && (!validateProperty(traits.key(), traits.value()))) {
659 qCCritical(lc).noquote() << tr(
"%1 property has invalid traits property").arg(name);
665 else if (name == QLatin1String(
"members")) {
666 if (!value.isObject()) {
667 qCCritical(lc).noquote() << tr(
"%1 property is not a JSON object").arg(name);
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());
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());
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());
693 else if (name == QLatin1String(
"version")) {
694 if (!value.isString()) {
695 qCCritical(lc).noquote() << tr(
"%1 property is not a JSON string").arg(name);
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);
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);
720 else if (name == QLatin1String(
"rename")) {
721 if (!value.isObject()) {
722 qCCritical(lc).noquote() << tr(
"%1 property is not a JSON object").arg(name);
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());
733 if (!iter.value().isString()) {
734 qCCritical(lc).noquote() << tr(
"%1 property has shape ID %2 with invalid value")
735 .arg(name, iter.key());
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);
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);
761 const QJsonObject shapeRef = value.toObject();
762 const auto target = shapeRef.constFind(QLatin1String(
"target"));
763 if (target == shapeRef.constEnd()) {
764 qCCritical(lc).noquote() << tr(
"%1 property has no target property").arg(name);
767 if (!target.value().isString()) {
768 qCCritical(lc).noquote() << tr(
"%1 property has target value that not a JSON string")
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);
779 if (shapeId.isRelativeShapeId()) {
780 qCCritical(lc).noquote() << tr(
"%1 property has target with relative shape ID %2")
781 .arg(name, shapeIdString);
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);
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());
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());
809 qCWarning(lc).noquote() << tr(
"Validation of %1 property not yet implemented").arg(name);
The ShapeId class provides a Qt representation of a Smithy Shape ID.
The ShapePrivate class provides private implementation for Shape.
Shape * q_ptr
Internal q-pointer.
ShapePrivate(Shape *const q)
The Shape class provides a Qt representation of a Smithy semantic shape.
@ IntEnum
An integer with a fixed set of values.
@ Document
Open content that functions as a kind of "any" type.
@ Float
Single precision IEEE-754 floating point number.
@ String
UTF-8 encoded string.
@ Boolean
Boolean value type.
@ Operation
Represents the input, output, and errors of an API operation.
@ Short
16-bit signed integer ranging from -32,768 to 32,767 (inclusive).
@ Map
Map data structure that maps string keys to homogeneous values.
@ List
Ordered collection of homogeneous values.
@ Set
Deprecated; use a list with the uniqueItems trait instead.
@ Long
64-bit signed integer ranging from -2^63 to (2^63)-1 (inclusive).
@ Apply
Traits to be applied to shapes outside of their definition.
@ Integer
32-bit signed integer ranging from -2^31 to (2^31)-1 (inclusive).
@ Byte
8-bit signed integer ranging from -128 to 127 (inclusive).
@ Timestamp
An instant in time with no UTC offset or timezone.
@ Resource
Entity with an identity that has a set of operations.
@ Service
Entry point of an API that aggregates resources and operations together.
@ Enum
A string with a fixed set of values.
@ BigInteger
Arbitrarily large signed integer.
@ Double
Double precision IEEE-754 floating point number.
@ Structure
Fixed set of named heterogeneous members.
@ Blob
Uninterpreted binary data.
@ BigDecimal
Arbitrary precision signed decimal number.
@ Undefined
The shape is undefined, usually the result of an error condition.
~Shape()
Destroys this Shape object.
Shape()
Constructs a new, empty Smithy shape.
#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.