< Summary

Information
Line coverage
0%
Covered lines: 0
Uncovered lines: 207
Coverable lines: 207
Total lines: 351
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 89
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
CreateFalseSchema()100%110%
CreateTrueSchema()100%110%
.ctor()100%110%
.ctor(...)100%110%
MakeNullable()0%440%
ToJsonNode(...)0%46460%
EnsureMutable(...)0%440%
VerifyMutable()0%220%
Throw()100%110%
MapSchemaType(...)0%880%
ToIdentifier(System.Text.Json.Schema.JsonSchemaType)0%15150%

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Schema\JsonSchema.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections.Generic;
 5using System.Diagnostics;
 6using System.Text.Json.Nodes;
 7
 8namespace System.Text.Json.Schema
 9{
 10    internal sealed class JsonSchema
 11    {
 12        internal const string RefPropertyName = "$ref";
 13        internal const string CommentPropertyName = "$comment";
 14        internal const string TypePropertyName = "type";
 15        internal const string FormatPropertyName = "format";
 16        internal const string PatternPropertyName = "pattern";
 17        internal const string PropertiesPropertyName = "properties";
 18        internal const string RequiredPropertyName = "required";
 19        internal const string ItemsPropertyName = "items";
 20        internal const string AdditionalPropertiesPropertyName = "additionalProperties";
 21        internal const string EnumPropertyName = "enum";
 22        internal const string NotPropertyName = "not";
 23        internal const string AnyOfPropertyName = "anyOf";
 24        internal const string ConstPropertyName = "const";
 25        internal const string DefaultPropertyName = "default";
 26        internal const string MinLengthPropertyName = "minLength";
 27        internal const string MaxLengthPropertyName = "maxLength";
 28
 029        public static JsonSchema CreateFalseSchema() => new(false);
 030        public static JsonSchema CreateTrueSchema() => new(true);
 31
 032        public JsonSchema() { }
 033        private JsonSchema(bool trueOrFalse) { _trueOrFalse = trueOrFalse; }
 34
 035        public bool IsTrue => _trueOrFalse is true;
 36        public bool IsFalse => _trueOrFalse is false;
 37
 38        /// <summary>
 39        /// Per the JSON schema core specification section 4.3
 40        /// (https://json-schema.org/draft/2020-12/json-schema-core#name-json-schema-documents)
 41        /// A JSON schema must either be an object or a boolean.
 42        /// We represent false and true schemas using this flag.
 43        /// It is not possible to specify keywords in boolean schemas.
 44        /// </summary>
 45        private readonly bool? _trueOrFalse;
 46
 047        public string? Ref { get => _ref; set { VerifyMutable(); _ref = value; } }
 48        private string? _ref;
 49
 050        public string? Comment { get => _comment; set { VerifyMutable(); _comment = value; } }
 51        private string? _comment;
 52
 053        public JsonSchemaType Type { get => _type; set { VerifyMutable(); _type = value; } }
 054        private JsonSchemaType _type = JsonSchemaType.Any;
 55
 056        public string? Format { get => _format; set { VerifyMutable(); _format = value; } }
 57        private string? _format;
 58
 059        public string? Pattern { get => _pattern; set { VerifyMutable(); _pattern = value; } }
 60        private string? _pattern;
 61
 062        public JsonNode? Constant { get => _constant; set { VerifyMutable(); _constant = value; } }
 63        private JsonNode? _constant;
 64
 065        public List<KeyValuePair<string, JsonSchema>>? Properties { get => _properties; set { VerifyMutable(); _properti
 66        private List<KeyValuePair<string, JsonSchema>>? _properties;
 67
 068        public List<string>? Required { get => _required; set { VerifyMutable(); _required = value; } }
 69        private List<string>? _required;
 70
 071        public JsonSchema? Items { get => _items; set { VerifyMutable(); _items = value; } }
 72        private JsonSchema? _items;
 73
 074        public JsonSchema? AdditionalProperties { get => _additionalProperties; set { VerifyMutable(); _additionalProper
 75        private JsonSchema? _additionalProperties;
 76
 077        public JsonArray? Enum { get => _enum; set { VerifyMutable(); _enum = value; } }
 78        private JsonArray? _enum;
 79
 080        public JsonSchema? Not { get => _not; set { VerifyMutable(); _not = value; } }
 81        private JsonSchema? _not;
 82
 083        public List<JsonSchema>? AnyOf { get => _anyOf; set { VerifyMutable(); _anyOf = value; } }
 84        private List<JsonSchema>? _anyOf;
 85
 086        public bool HasDefaultValue { get => _hasDefaultValue; set { VerifyMutable(); _hasDefaultValue = value; } }
 87        private bool _hasDefaultValue;
 88
 089        public JsonNode? DefaultValue { get => _defaultValue; set { VerifyMutable(); _defaultValue = value; } }
 90        private JsonNode? _defaultValue;
 91
 092        public int? MinLength { get => _minLength; set { VerifyMutable(); _minLength = value; } }
 93        private int? _minLength;
 94
 095        public int? MaxLength { get => _maxLength; set { VerifyMutable(); _maxLength = value; } }
 96        private int? _maxLength;
 97
 098        public JsonSchemaExporterContext? ExporterContext { get; set; }
 99
 100        public int KeywordCount
 101        {
 102            get
 0103            {
 0104                if (_trueOrFalse != null)
 0105                {
 106                    // Boolean schemas admit no keywords
 0107                    return 0;
 108                }
 109
 0110                int count = 0;
 0111                Count(Ref != null);
 0112                Count(Comment != null);
 0113                Count(Type != JsonSchemaType.Any);
 0114                Count(Format != null);
 0115                Count(Pattern != null);
 0116                Count(Constant != null);
 0117                Count(Properties != null);
 0118                Count(Required != null);
 0119                Count(Items != null);
 0120                Count(AdditionalProperties != null);
 0121                Count(Enum != null);
 0122                Count(Not != null);
 0123                Count(AnyOf != null);
 0124                Count(HasDefaultValue);
 0125                Count(MinLength != null);
 0126                Count(MaxLength != null);
 127
 0128                return count;
 129
 130                void Count(bool isKeywordSpecified)
 0131                {
 0132                    count += isKeywordSpecified ? 1 : 0;
 0133                }
 0134            }
 135        }
 136
 137        public void MakeNullable()
 0138        {
 0139            if (_trueOrFalse != null)
 0140            {
 141                // boolean schemas do not admit type keywords.
 0142                return;
 143            }
 144
 0145            if (Type != JsonSchemaType.Any)
 0146            {
 0147                Type |= JsonSchemaType.Null;
 0148            }
 0149        }
 150
 151        public JsonNode ToJsonNode(JsonSchemaExporterOptions options)
 0152        {
 0153            if (_trueOrFalse is { } boolSchema)
 0154            {
 0155                return CompleteSchema((JsonNode)boolSchema);
 156            }
 157
 0158            var objSchema = new JsonObject();
 159
 0160            if (Ref != null)
 0161            {
 0162                objSchema.Add(RefPropertyName, Ref);
 0163            }
 164
 0165            if (Comment != null)
 0166            {
 0167                objSchema.Add(CommentPropertyName, Comment);
 0168            }
 169
 0170            if (MapSchemaType(Type) is JsonNode type)
 0171            {
 0172                objSchema.Add(TypePropertyName, type);
 0173            }
 174
 0175            if (Format != null)
 0176            {
 0177                objSchema.Add(FormatPropertyName, Format);
 0178            }
 179
 0180            if (Pattern != null)
 0181            {
 0182                objSchema.Add(PatternPropertyName, Pattern);
 0183            }
 184
 0185            if (Constant != null)
 0186            {
 0187                objSchema.Add(ConstPropertyName, Constant);
 0188            }
 189
 0190            if (Properties != null)
 0191            {
 0192                var properties = new JsonObject();
 0193                foreach (KeyValuePair<string, JsonSchema> property in Properties)
 0194                {
 0195                    properties.Add(property.Key, property.Value.ToJsonNode(options));
 0196                }
 197
 0198                objSchema.Add(PropertiesPropertyName, properties);
 0199            }
 200
 0201            if (Required != null)
 0202            {
 0203                var requiredArray = new JsonArray();
 0204                foreach (string requiredProperty in Required)
 0205                {
 0206                    requiredArray.Add((JsonNode)requiredProperty);
 0207                }
 208
 0209                objSchema.Add(RequiredPropertyName, requiredArray);
 0210            }
 211
 0212            if (Items != null)
 0213            {
 0214                objSchema.Add(ItemsPropertyName, Items.ToJsonNode(options));
 0215            }
 216
 0217            if (AdditionalProperties != null)
 0218            {
 0219                objSchema.Add(AdditionalPropertiesPropertyName, AdditionalProperties.ToJsonNode(options));
 0220            }
 221
 0222            if (Enum != null)
 0223            {
 0224                objSchema.Add(EnumPropertyName, Enum);
 0225            }
 226
 0227            if (Not != null)
 0228            {
 0229                objSchema.Add(NotPropertyName, Not.ToJsonNode(options));
 0230            }
 231
 0232            if (AnyOf != null)
 0233            {
 0234                JsonArray anyOfArray = [];
 0235                foreach (JsonSchema schema in AnyOf)
 0236                {
 0237                    anyOfArray.Add(schema.ToJsonNode(options));
 0238                }
 239
 0240                objSchema.Add(AnyOfPropertyName, anyOfArray);
 0241            }
 242
 0243            if (HasDefaultValue)
 0244            {
 0245                objSchema.Add(DefaultPropertyName, DefaultValue);
 0246            }
 247
 0248            if (MinLength is int minLength)
 0249            {
 0250                objSchema.Add(MinLengthPropertyName, (JsonNode)minLength);
 0251            }
 252
 0253            if (MaxLength is int maxLength)
 0254            {
 0255                objSchema.Add(MaxLengthPropertyName, (JsonNode)maxLength);
 0256            }
 257
 0258            return CompleteSchema(objSchema);
 259
 260            JsonNode CompleteSchema(JsonNode schema)
 0261            {
 0262                if (ExporterContext is { } context)
 0263                {
 0264                    Debug.Assert(options.TransformSchemaNode != null, "context should only be populated if a callback is
 265                    // Apply any user-defined transformations to the schema.
 0266                    return options.TransformSchemaNode(context, schema);
 267                }
 268
 0269                return schema;
 0270            }
 0271        }
 272
 273        /// <summary>
 274        /// If the schema is boolean, replaces it with a semantically
 275        /// equivalent object schema that allows appending keywords.
 276        /// </summary>
 277        public static void EnsureMutable(ref JsonSchema schema)
 0278        {
 0279            switch (schema._trueOrFalse)
 280            {
 281                case false:
 0282                    schema = new JsonSchema { Not = CreateTrueSchema() };
 0283                    break;
 284                case true:
 0285                    schema = new JsonSchema();
 0286                    break;
 287            }
 0288        }
 289
 290        private static ReadOnlySpan<JsonSchemaType> s_schemaValues =>
 0291        [
 0292            // NB the order of these values influences order of types in the rendered schema
 0293            JsonSchemaType.String,
 0294            JsonSchemaType.Integer,
 0295            JsonSchemaType.Number,
 0296            JsonSchemaType.Boolean,
 0297            JsonSchemaType.Array,
 0298            JsonSchemaType.Object,
 0299            JsonSchemaType.Null,
 0300        ];
 301
 302        private void VerifyMutable()
 0303        {
 0304            Debug.Assert(_trueOrFalse is null, "Schema is not mutable");
 0305            if (_trueOrFalse is not null)
 0306            {
 0307                Throw();
 0308                static void Throw() => throw new InvalidOperationException();
 0309            }
 0310        }
 311
 312        public static JsonNode? MapSchemaType(JsonSchemaType schemaType)
 0313        {
 0314            if (schemaType is JsonSchemaType.Any)
 0315            {
 0316                return null;
 317            }
 318
 0319            if (ToIdentifier(schemaType) is string identifier)
 0320            {
 0321                return identifier;
 322            }
 323
 0324            var array = new JsonArray();
 0325            foreach (JsonSchemaType type in s_schemaValues)
 0326            {
 0327                if ((schemaType & type) != 0)
 0328                {
 0329                    array.Add((JsonNode)ToIdentifier(type)!);
 0330                }
 0331            }
 332
 0333            return array;
 334
 335            static string? ToIdentifier(JsonSchemaType schemaType)
 0336            {
 0337                return schemaType switch
 0338                {
 0339                    JsonSchemaType.Null => "null",
 0340                    JsonSchemaType.Boolean => "boolean",
 0341                    JsonSchemaType.Integer => "integer",
 0342                    JsonSchemaType.Number => "number",
 0343                    JsonSchemaType.String => "string",
 0344                    JsonSchemaType.Array => "array",
 0345                    JsonSchemaType.Object => "object",
 0346                    _ => null,
 0347                };
 0348            }
 0349        }
 350    }
 351}