in src/AutoRest.CSharp/Common/Decorator/SchemaUsageTransformer.cs [21:113]
public static void Transform(CodeModel codeModel)
{
Dictionary<string, List<Property>> schemaToPropertyMap = new();
Dictionary<string, List<Schema>> schemaToEnclosingSchemasMap = new();
foreach (var schema in codeModel.AllSchemas.OfType<ObjectSchema>())
{
foreach (var property in schema.Properties)
{
if (property.Extensions?.TryGetValue(FormatElementDefinition, out var value) == true)
{
string valueString = (string)value;
if (valueString.StartsWith("#/definitions/"))
{
valueString = valueString.Substring("#/definitions/".Length);
}
if (!schemaToPropertyMap.ContainsKey(valueString))
{
schemaToPropertyMap.Add(valueString, new List<Property>());
}
if (!schemaToEnclosingSchemasMap.ContainsKey(valueString))
{
schemaToEnclosingSchemasMap.Add(valueString, new List<Schema>());
}
schemaToPropertyMap[valueString].Add(property);
schemaToEnclosingSchemasMap[valueString].Add(schema);
}
}
}
if (schemaToPropertyMap.Count == 0)
return;
foreach (var schema in codeModel.AllSchemas.OfType<ObjectSchema>())
{
if (!schemaToPropertyMap.TryGetValue(schema.Name, out var propertyList)) continue;
schemaToPropertyMap.Remove(schema.Name);
foreach (var property in propertyList)
{
property.Extensions![FormatElementDefinition] = schema;
}
schema.Extensions ??= new RecordOfStringAndAny();
// apply usages and media types based on the enclosing schemas for the properties that reference
// the "x-ms-format-element-type" schema
HashSet<string> additionalUsages = new();
HashSet<KnownMediaType> additionalMediaTypes = new();
foreach (var enclosingSchema in schemaToEnclosingSchemasMap[schema.Name])
{
if (enclosingSchema is ObjectSchema objectSchema)
{
foreach (SchemaContext schemaUsage in objectSchema.Usage)
{
if (schemaUsage == SchemaContext.Exception) continue;
additionalUsages.Add(schemaUsage == SchemaContext.Input ? "input" : "output");
}
foreach (KnownMediaType mediaType in objectSchema.SerializationFormats)
{
additionalMediaTypes.Add(mediaType);
}
}
}
if (additionalUsages.Count > 0)
{
// This is a hack to avoid needing to update the SchemaUsageProvider logic to look up the property schema using "x-ms-format-element-type"
// The problem with doing this here is that we don't know for sure if this should be a public model, but if we don't mark is as a model
// here then it will be generated as internal, since it will not necessarily be included in the SchemaUsageProvider logic that
// loops through model properties.
additionalUsages.Add("model");
}
// apply converter usage to any schemas that are referenced with "x-ms-format-element-type" in a property
additionalUsages.Add("converter");
// recursively apply the usages and media types to the schema and all property schemas on the schema
Apply(schema, string.Join(",", additionalUsages), additionalMediaTypes, new HashSet<ObjectSchema>());
}
if (schemaToPropertyMap.Count > 0)
{
var schemaList = schemaToPropertyMap.Keys.Aggregate((a, b) => $"{a}, {b}");
throw new InvalidOperationException($"The following schemas were referenced by properties with the '{FormatElementDefinition}' attribute, but were not found in any definitions: " + schemaList);
}
}