/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #pragma once #include "utils_global.h" #include #include #include #include QT_FORWARD_DECLARE_CLASS(QVariant) namespace Utils { class JsonStringValue; class JsonDoubleValue; class JsonIntValue; class JsonObjectValue; class JsonArrayValue; class JsonBooleanValue; class JsonNullValue; class QTCREATOR_UTILS_EXPORT JsonMemoryPool { public: ~JsonMemoryPool(); inline void *allocate(size_t size) { auto obj = new char[size]; _objs.append(obj); return obj; } private: QVector _objs; }; /*! * \brief The JsonValue class */ class QTCREATOR_UTILS_EXPORT JsonValue { public: enum Kind { String, Double, Int, Object, Array, Boolean, Null, Unknown }; virtual ~JsonValue(); Kind kind() const { return m_kind; } static QString kindToString(Kind kind); virtual JsonStringValue *toString() { return nullptr; } virtual JsonDoubleValue *toDouble() { return nullptr; } virtual JsonIntValue *toInt() { return nullptr; } virtual JsonObjectValue *toObject() { return nullptr; } virtual JsonArrayValue *toArray() { return nullptr; } virtual JsonBooleanValue *toBoolean() { return nullptr; } virtual JsonNullValue *toNull() { return nullptr; } static JsonValue *create(const QString &s, JsonMemoryPool *pool); void *operator new(size_t size, JsonMemoryPool *pool); void operator delete(void *); void operator delete(void *, JsonMemoryPool *); protected: JsonValue(Kind kind); private: static JsonValue *build(const QVariant &varixant, JsonMemoryPool *pool); Kind m_kind; }; /*! * \brief The JsonStringValue class */ class QTCREATOR_UTILS_EXPORT JsonStringValue : public JsonValue { public: JsonStringValue(const QString &value) : JsonValue(String) , m_value(value) {} JsonStringValue *toString() override { return this; } const QString &value() const { return m_value; } private: QString m_value; }; /*! * \brief The JsonDoubleValue class */ class QTCREATOR_UTILS_EXPORT JsonDoubleValue : public JsonValue { public: JsonDoubleValue(double value) : JsonValue(Double) , m_value(value) {} JsonDoubleValue *toDouble() override { return this; } double value() const { return m_value; } private: double m_value; }; /*! * \brief The JsonIntValue class */ class QTCREATOR_UTILS_EXPORT JsonIntValue : public JsonValue { public: JsonIntValue(int value) : JsonValue(Int) , m_value(value) {} JsonIntValue *toInt() override { return this; } int value() const { return m_value; } private: int m_value; }; /*! * \brief The JsonObjectValue class */ class QTCREATOR_UTILS_EXPORT JsonObjectValue : public JsonValue { public: JsonObjectValue() : JsonValue(Object) {} JsonObjectValue *toObject() override { return this; } void addMember(const QString &name, JsonValue *value) { m_members.insert(name, value); } bool hasMember(const QString &name) const { return m_members.contains(name); } JsonValue *member(const QString &name) const { return m_members.value(name); } QHash members() const { return m_members; } bool isEmpty() const { return m_members.isEmpty(); } protected: JsonObjectValue(Kind kind) : JsonValue(kind) {} private: QHash m_members; }; /*! * \brief The JsonArrayValue class */ class QTCREATOR_UTILS_EXPORT JsonArrayValue : public JsonValue { public: JsonArrayValue() : JsonValue(Array) {} JsonArrayValue *toArray() override { return this; } void addElement(JsonValue *value) { m_elements.append(value); } QList elements() const { return m_elements; } int size() const { return m_elements.size(); } private: QList m_elements; }; /*! * \brief The JsonBooleanValue class */ class QTCREATOR_UTILS_EXPORT JsonBooleanValue : public JsonValue { public: JsonBooleanValue(bool value) : JsonValue(Boolean) , m_value(value) {} JsonBooleanValue *toBoolean() override { return this; } bool value() const { return m_value; } private: bool m_value; }; class QTCREATOR_UTILS_EXPORT JsonNullValue : public JsonValue { public: JsonNullValue() : JsonValue(Null) {} JsonNullValue *toNull() override { return this; } }; class JsonSchemaManager; /*! * \brief The JsonSchema class * * [NOTE: This is an incomplete implementation and a work in progress.] * * This class provides an interface for traversing and evaluating a JSON schema, as described * in the draft http://tools.ietf.org/html/draft-zyp-json-schema-03. * * JSON schemas are recursive in concept. This means that a particular attribute from a schema * might be also another schema. Therefore, the basic working principle of this API is that * from within some schema, one can investigate its attributes and if necessary "enter" a * corresponding nested schema. Afterwards, it's expected that one would "leave" such nested * schema. * * All functions assume that the current "context" is a valid schema. Once an instance of this * class is created the root schema is put on top of the stack. * */ class QTCREATOR_UTILS_EXPORT JsonSchema { public: bool isTypeConstrained() const; bool acceptsType(const QString &type) const; QStringList validTypes() const; // Applicable on schemas of any type. bool required() const; bool hasTypeSchema() const; void enterNestedTypeSchema(); bool hasUnionSchema() const; int unionSchemaSize() const; bool maybeEnterNestedUnionSchema(int index); void leaveNestedSchema(); // Applicable on schemas of type number/integer. bool hasMinimum() const; bool hasMaximum() const; bool hasExclusiveMinimum(); bool hasExclusiveMaximum(); double minimum() const; double maximum() const; // Applicable on schemas of type string. QString pattern() const; int minimumLength() const; int maximumLength() const; // Applicable on schemas of type object. QStringList properties() const; bool hasPropertySchema(const QString &property) const; void enterNestedPropertySchema(const QString &property); // Applicable on schemas of type array. bool hasAdditionalItems() const; bool hasItemSchema() const; void enterNestedItemSchema(); bool hasItemArraySchema() const; int itemArraySchemaSize() const; bool maybeEnterNestedArraySchema(int index); private: friend class JsonSchemaManager; JsonSchema(JsonObjectValue *rootObject, const JsonSchemaManager *manager); Q_DISABLE_COPY(JsonSchema) enum EvaluationMode { Normal, Array, Union }; void enter(JsonObjectValue *ov, EvaluationMode eval = Normal, int index = -1); bool maybeEnter(JsonValue *v, EvaluationMode eval, int index); void evaluate(EvaluationMode eval, int index); void leave(); JsonObjectValue *resolveReference(JsonObjectValue *ov) const; JsonObjectValue *resolveBase(JsonObjectValue *ov) const; JsonObjectValue *currentValue() const; int currentIndex() const; JsonObjectValue *rootValue() const; static JsonStringValue *getStringValue(const QString &name, JsonObjectValue *value); static JsonObjectValue *getObjectValue(const QString &name, JsonObjectValue *value); static JsonBooleanValue *getBooleanValue(const QString &name, JsonObjectValue *value); static JsonArrayValue *getArrayValue(const QString &name, JsonObjectValue *value); static JsonDoubleValue *getDoubleValue(const QString &name, JsonObjectValue *value); static QStringList validTypes(JsonObjectValue *v); static bool typeMatches(const QString &expected, const QString &actual); static bool isCheckableType(const QString &s); QStringList properties(JsonObjectValue *v) const; JsonObjectValue *propertySchema(const QString &property, JsonObjectValue *v) const; // TODO: Similar functions for other attributes which require looking into base schemas. static bool maybeSchemaName(const QString &s); static QString kType(); static QString kProperties(); static QString kPatternProperties(); static QString kAdditionalProperties(); static QString kItems(); static QString kAdditionalItems(); static QString kRequired(); static QString kDependencies(); static QString kMinimum(); static QString kMaximum(); static QString kExclusiveMinimum(); static QString kExclusiveMaximum(); static QString kMinItems(); static QString kMaxItems(); static QString kUniqueItems(); static QString kPattern(); static QString kMinLength(); static QString kMaxLength(); static QString kTitle(); static QString kDescription(); static QString kExtends(); static QString kRef(); struct Context { JsonObjectValue *m_value; EvaluationMode m_eval; int m_index; }; QVector m_schemas; const JsonSchemaManager *m_manager; }; /*! * \brief The JsonSchemaManager class */ class QTCREATOR_UTILS_EXPORT JsonSchemaManager { public: JsonSchemaManager(const QStringList &searchPaths); ~JsonSchemaManager(); JsonSchema *schemaForFile(const QString &fileName) const; JsonSchema *schemaByName(const QString &baseName) const; private: struct JsonSchemaData { JsonSchemaData(const QString &absoluteFileName, JsonSchema *schema = nullptr) : m_absoluteFileName(absoluteFileName) , m_schema(schema) {} QString m_absoluteFileName; JsonSchema *m_schema; QDateTime m_lastParseAttempt; }; JsonSchema *parseSchema(const QString &schemaFileName) const; QStringList m_searchPaths; mutable QHash m_schemas; mutable JsonMemoryPool m_pool; }; } // namespace Utils