public ChangedPathBO Diff(OpenApiPathItem left, OpenApiPathItem right, DiffContextBO context) { var oldOperationMap = left.Operations; var newOperationMap = right.Operations; var operationsDiff = MapKeyDiff <OperationType, OpenApiOperation> .Diff(oldOperationMap, newOperationMap); var sharedMethods = operationsDiff.SharedKey; var changedPath = new ChangedPathBO(context.URL, left, right, context) { Increased = operationsDiff.Increased, Missing = operationsDiff.Missing }; foreach (var operationType in sharedMethods) { var oldOperation = oldOperationMap[operationType]; var newOperation = newOperationMap[operationType]; var diff = _openApiDiff .OperationDiff .Diff(oldOperation, newOperation, context.CopyWithMethod(operationType)); if (diff != null) { changedPath.Changed.Add(diff); } } changedPath.Extensions = _openApiDiff .ExtensionsDiff .Diff(left.Extensions, right.Extensions, context); return(ChangedUtils.IsChanged(changedPath)); }
public TD CachedDiff( TC left, TC right, string leftRef, string rightRef, DiffContextBO context) { var areBothRefParameters = leftRef != null && rightRef != null; if (areBothRefParameters) { var key = new CacheKey(leftRef, rightRef, context); if (RefDiffMap.TryGetValue(key, out var changedFromRef)) { return(changedFromRef); } RefDiffMap.Add(key, null); var changed = ComputeDiff(left, right, context); RefDiffMap[key] = changed; return(changed); } return(ComputeDiff(left, right, context)); }
protected override ChangedHeaderBO ComputeDiff(OpenApiHeader left, OpenApiHeader right, DiffContextBO context) { left = RefPointer.ResolveRef(_leftComponents, left, left.Reference?.ReferenceV3); right = RefPointer.ResolveRef(_rightComponents, right, right.Reference?.ReferenceV3); var changedHeader = new ChangedHeaderBO(left, right, context) { Required = GetBooleanDiff(left.Required, right.Required), Deprecated = !left.Deprecated && right.Deprecated, Style = left.Style != right.Style, Explode = GetBooleanDiff(left.Explode, right.Explode), Description = _openApiDiff .MetadataDiff .Diff(left.Description, right.Description, context), Schema = _openApiDiff .SchemaDiff .Diff(left.Schema, right.Schema, context.CopyWithRequired(true)), Content = _openApiDiff .ContentDiff .Diff(left.Content, right.Content, context), Extensions = _openApiDiff .ExtensionsDiff .Diff(left.Extensions, right.Extensions, context) }; return(ChangedUtils.IsChanged(changedHeader)); }
private void CompareAdditionalProperties(OpenApiSchema leftSchema, OpenApiSchema rightSchema, DiffContextBO context) { var left = leftSchema.AdditionalProperties; var right = rightSchema.AdditionalProperties; if (left != null || right != null) { var apChangedSchema = new ChangedSchemaBO { Context = context, OldSchema = left, NewSchema = right }; if (left != null && right != null) { var addPropChangedSchemaOp = OpenApiDiff .SchemaDiff .Diff(left, right, context.CopyWithRequired(false)); apChangedSchema = addPropChangedSchemaOp ?? apChangedSchema; } var changed = ChangedUtils.IsChanged(apChangedSchema); if (changed != null) { ChangedSchema.AddProp = changed; } } }
public ChangedHeadersBO Diff(IDictionary <string, OpenApiHeader> left, IDictionary <string, OpenApiHeader> right, DiffContextBO context) { var headerMapDiff = MapKeyDiff <string, OpenApiHeader> .Diff(left, right); var sharedHeaderKeys = headerMapDiff.SharedKey; var changed = new Dictionary <string, ChangedHeaderBO>(); foreach (var headerKey in sharedHeaderKeys) { var oldHeader = left[headerKey]; var newHeader = right[headerKey]; var changedHeaders = _openApiDiff .HeaderDiff .Diff(oldHeader, newHeader, context); if (changedHeaders != null) { changed.Add(headerKey, changedHeaders); } } return(ChangedUtils.IsChanged( new ChangedHeadersBO(left, right, context) { Increased = headerMapDiff.Increased, Missing = headerMapDiff.Missing, Changed = changed })); }
public ChangedSchemaBO Diff(OpenApiSchema left, OpenApiSchema right, DiffContextBO context) { if (left == null && right == null) { return(null); } var leftRef = GetSchemaRef(left); var rightRef = GetSchemaRef(right); if (left != null && left.AllOf.Any()) { var result = ResolveComposedSchema(_leftComponents, left); leftRef = result.Key; left = result.Value; } if (right != null && right.AllOf.Any()) { var result = ResolveComposedSchema(_rightComponents, right); rightRef = result.Key; right = result.Value; } return(CachedDiff(left, right, leftRef, rightRef, context)); }
public override ChangedSchemaBO Diff <T>(OpenApiComponents leftComponents, OpenApiComponents rightComponents, T left, T right, DiffContextBO context) { if (left.GetSchemaType() != SchemaTypeEnum.ArraySchema || right.GetSchemaType() != SchemaTypeEnum.ArraySchema) { return(null); } base.Diff(leftComponents, rightComponents, left, right, context); var diff = OpenApiDiff .SchemaDiff .Diff( left.Items, right.Items, context.CopyWithRequired(true)); if (diff != null) { ChangedSchema.Items = diff; } return(IsApplicable(context)); }
public ChangedRequestBodyBO Diff( OpenApiRequestBody left, OpenApiRequestBody right, DiffContextBO context) { var leftRef = left.Reference?.ReferenceV3; var rightRef = right.Reference?.ReferenceV3; return(CachedDiff(left, right, leftRef, rightRef, context)); }
public ChangedPathsBO Diff(Dictionary <string, OpenApiPathItem> left, Dictionary <string, OpenApiPathItem> right) { var changedPaths = new ChangedPathsBO(left, right); foreach (var(key, value) in right) { changedPaths.Increased.Add(key, value); } foreach (var(key, value) in left) { var template = key.NormalizePath(); var result = right.Keys.FirstOrDefault(x => x.NormalizePath() == template); if (result != null) { if (!changedPaths.Increased.ContainsKey(result)) { throw new ArgumentException($"Two path items have the same signature: {template}"); } var rightPath = changedPaths.Increased[result]; changedPaths.Increased.Remove(result); var paramsDict = new Dictionary <string, string>(); if (key != result) { var oldParams = key.ExtractParametersFromPath(); var newParams = result.ExtractParametersFromPath(); for (var i = oldParams.Count - 1; i >= 0; i--) { paramsDict.Add(oldParams[i], newParams[i]); } } var context = new DiffContextBO { URL = key, Parameters = paramsDict }; var diff = _openApiDiff .PathDiff .Diff(value, rightPath, context); if (diff != null) { changedPaths.Changed.Add(result, diff); } } else { changedPaths.Missing.Add(key, value); } } return(ChangedUtils.IsChanged(changedPaths)); }
protected override ChangedRequestBodyBO ComputeDiff(OpenApiRequestBody left, OpenApiRequestBody right, DiffContextBO context) { Dictionary <string, OpenApiMediaType> oldRequestContent = null; Dictionary <string, OpenApiMediaType> newRequestContent = null; OpenApiRequestBody oldRequestBody = null; OpenApiRequestBody newRequestBody = null; if (left != null) { oldRequestBody = RefPointer.ResolveRef( _openApiDiff.OldSpecOpenApi.Components, left, left.Reference?.ReferenceV3); if (oldRequestBody.Content != null) { oldRequestContent = (Dictionary <string, OpenApiMediaType>)oldRequestBody.Content; } } if (right != null) { newRequestBody = RefPointer.ResolveRef( _openApiDiff.NewSpecOpenApi.Components, right, right.Reference?.ReferenceV3); if (newRequestBody.Content != null) { newRequestContent = (Dictionary <string, OpenApiMediaType>)newRequestBody.Content; } } var leftRequired = oldRequestBody != null && oldRequestBody.Required; var rightRequired = newRequestBody != null && newRequestBody.Required; var changedRequestBody = new ChangedRequestBodyBO(oldRequestBody, newRequestBody, context) { ChangeRequired = leftRequired != rightRequired, Description = _openApiDiff .MetadataDiff .Diff( oldRequestBody?.Description, newRequestBody?.Description, context), Content = _openApiDiff .ContentDiff .Diff(oldRequestContent, newRequestContent, context), Extensions = _openApiDiff .ExtensionsDiff .Diff(GetExtensions(left), GetExtensions(right), context) }; return(ChangedUtils.IsChanged(changedRequestBody)); }
protected ChangedSchemaBO IsApplicable(DiffContextBO context) { if (ChangedSchema.ReadOnly.IsUnchanged() && ChangedSchema.WriteOnly.IsUnchanged() && !IsPropertyApplicable(ChangedSchema.NewSchema, context)) { return(null); } return(ChangedUtils.IsChanged(ChangedSchema)); }
public ChangedSchemaBO GetTypeChangedSchema( OpenApiSchema left, OpenApiSchema right, DiffContextBO context) { var schemaDiffResult = GetSchemaDiffResult(_openApiDiff); schemaDiffResult.ChangedSchema.OldSchema = left; schemaDiffResult.ChangedSchema.NewSchema = right; schemaDiffResult.ChangedSchema.IsChangedType = true; schemaDiffResult.ChangedSchema.Context = context; return(schemaDiffResult.ChangedSchema); }
public bool IsParentApplicable(TypeEnum type, object parent, IDictionary <string, IOpenApiExtension> extensions, DiffContextBO context) { if (extensions.IsNullOrEmpty()) { return(true); } return(extensions.Select(x => ExecuteExtension(x.Key, y => y .IsParentApplicable(type, parent, x.Value, context))) .All(x => x)); }
private static string Properties(string propPrefix, string title, Dictionary <string, OpenApiSchema> properties, DiffContextBO context) { var sb = new StringBuilder(); if (properties != null) { foreach (var(key, value) in properties) { sb.Append(Property(propPrefix + key, title, Resolve(value))); } } return(sb.ToString()); }
protected override ChangedSecuritySchemeBO ComputeDiff( OpenApiSecurityScheme leftSecurityScheme, OpenApiSecurityScheme rightSecurityScheme, DiffContextBO context) { var changedSecurityScheme = new ChangedSecuritySchemeBO(leftSecurityScheme, rightSecurityScheme) { Description = _openApiDiff .MetadataDiff .Diff(leftSecurityScheme.Description, rightSecurityScheme.Description, context) }; switch (leftSecurityScheme.Type) { case SecuritySchemeType.ApiKey: changedSecurityScheme.IsChangedIn = !leftSecurityScheme.In.Equals(rightSecurityScheme.In); break; case SecuritySchemeType.Http: changedSecurityScheme.IsChangedScheme = leftSecurityScheme.Scheme != rightSecurityScheme.Scheme; changedSecurityScheme.IsChangedBearerFormat = leftSecurityScheme.BearerFormat != rightSecurityScheme.BearerFormat; break; case SecuritySchemeType.OAuth2: changedSecurityScheme.OAuthFlows = _openApiDiff .OAuthFlowsDiff .Diff(leftSecurityScheme.Flows, rightSecurityScheme.Flows); break; case SecuritySchemeType.OpenIdConnect: changedSecurityScheme.IsChangedOpenIdConnectUrl = leftSecurityScheme.OpenIdConnectUrl != rightSecurityScheme.OpenIdConnectUrl; break; default: throw new ArgumentOutOfRangeException(); } changedSecurityScheme.Extensions = _openApiDiff .ExtensionsDiff .Diff(leftSecurityScheme.Extensions, rightSecurityScheme.Extensions, context); return(changedSecurityScheme); }
public ChangedSecurityRequirementBO Diff( OpenApiSecurityRequirement left, OpenApiSecurityRequirement right, DiffContextBO context) { var changedSecurityRequirement = new ChangedSecurityRequirementBO(left, right != null ? GetCopy(right) : null); left ??= new OpenApiSecurityRequirement(); right ??= new OpenApiSecurityRequirement(); foreach (var(key, value) in left) { var rightSec = Contains(right, key.Reference?.ReferenceV3); if (rightSec.IsNullOrEmpty()) { changedSecurityRequirement.Missing.Add(key, value); } else { var rightSchemeRef = rightSec.Keys.First(); right.Remove(rightSchemeRef); var diff = _openApiDiff .SecuritySchemeDiff .Diff( key.Reference?.ReferenceV3, value.ToList(), rightSchemeRef.Reference?.ReferenceV3, rightSec[rightSchemeRef].ToList(), context); if (diff != null) { changedSecurityRequirement.Changed.Add(diff); } } } foreach (var(key, value) in right) { changedSecurityRequirement.Increased.Add(key, value); } return(ChangedUtils.IsChanged(changedSecurityRequirement)); }
public ChangedParametersBO Diff( List <OpenApiParameter> left, List <OpenApiParameter> right, DiffContextBO context) { var changedParameters = new ChangedParametersBO(left, right, context); if (null == left) { left = new List <OpenApiParameter>(); } if (null == right) { right = new List <OpenApiParameter>(); } foreach (var openApiParameter in left) { var leftPara = openApiParameter; leftPara = RefPointer.ResolveRef(_leftComponents, leftPara, leftPara.Reference?.ReferenceV3); var rightParam = Contains(_rightComponents, right, leftPara); if (rightParam == null) { changedParameters.Missing.Add(leftPara); } else { right.Remove(rightParam); var diff = _openApiDiff.ParameterDiff .Diff(leftPara, rightParam, context); if (diff != null) { changedParameters.Changed.Add(diff); } } } changedParameters.Increased.AddRange(right); return(ChangedUtils.IsChanged(changedParameters)); }
public ChangedContentBO Diff(IDictionary <string, OpenApiMediaType> left, IDictionary <string, OpenApiMediaType> right, DiffContextBO context) { var leftDict = (Dictionary <string, OpenApiMediaType>)left; var rightDict = (Dictionary <string, OpenApiMediaType>)right; var mediaTypeDiff = MapKeyDiff <string, OpenApiMediaType> .Diff(leftDict, rightDict); var sharedMediaTypes = mediaTypeDiff.SharedKey; var changedMediaTypes = new Dictionary <string, ChangedMediaTypeBO>(); foreach (var sharedMediaType in sharedMediaTypes) { var oldMediaType = left[sharedMediaType]; var newMediaType = right[sharedMediaType]; var changedMediaType = new ChangedMediaTypeBO(oldMediaType?.Schema, newMediaType?.Schema, context) { Schema = _openApiDiff .SchemaDiff .Diff( oldMediaType?.Schema, newMediaType?.Schema, context.CopyWithRequired(true)) }; if (!ChangedUtils.IsUnchanged(changedMediaType)) { changedMediaTypes.Add(sharedMediaType, changedMediaType); } } return(ChangedUtils.IsChanged(new ChangedContentBO(leftDict, rightDict, context) { Increased = mediaTypeDiff.Increased, Missing = mediaTypeDiff.Missing, Changed = changedMediaTypes })); }
public ChangedSecuritySchemeBO Diff( string leftSchemeRef, List <string> leftScopes, string rightSchemeRef, List <string> rightScopes, DiffContextBO context) { var leftSecurityScheme = _leftComponents.SecuritySchemes[leftSchemeRef]; var rightSecurityScheme = _rightComponents.SecuritySchemes[rightSchemeRef]; var changedSecuritySchemeOpt = CachedDiff( leftSecurityScheme, rightSecurityScheme, leftSchemeRef, rightSchemeRef, context); var changedSecurityScheme = changedSecuritySchemeOpt ?? new ChangedSecuritySchemeBO(leftSecurityScheme, rightSecurityScheme); changedSecurityScheme = GetCopyWithoutScopes(changedSecurityScheme); if (changedSecurityScheme != null && leftSecurityScheme.Type == SecuritySchemeType.OAuth2) { var changed = ChangedUtils.IsChanged(ListDiff.Diff( new ChangedSecuritySchemeScopesBO(leftScopes, rightScopes) )); if (changed != null) { changedSecurityScheme.ChangedScopes = changed; } } return(ChangedUtils.IsChanged(changedSecurityScheme)); }
protected override ChangedResponseBO ComputeDiff(OpenApiResponse left, OpenApiResponse right, DiffContextBO context) { left = RefPointer.ResolveRef(_leftComponents, left, left.Reference?.ReferenceV3); right = RefPointer.ResolveRef(_rightComponents, right, right.Reference?.ReferenceV3); var changedResponse = new ChangedResponseBO(left, right, context) { Description = _openApiDiff .MetadataDiff .Diff(left.Description, right.Description, context), Content = _openApiDiff .ContentDiff .Diff(left.Content, right.Content, context), Headers = _openApiDiff .HeadersDiff .Diff(left.Headers, right.Headers, context), Extensions = _openApiDiff .ExtensionsDiff .Diff(left.Extensions, right.Extensions, context) }; return(ChangedUtils.IsChanged(changedResponse)); }
public ChangedHeaderBO Diff(OpenApiHeader left, OpenApiHeader right, DiffContextBO context) { return(CachedDiff(left, right, left.Reference?.ReferenceV3, right.Reference?.ReferenceV3, context)); }
private static DiffContextBO Required(DiffContextBO context, string key, ICollection <string> required) { return(context.CopyWithRequired(required != null && required.Contains(key))); }
public ChangedAPIResponseBO Diff(OpenApiResponses left, OpenApiResponses right, DiffContextBO context) { var responseMapKeyDiff = MapKeyDiff <string, OpenApiResponse> .Diff(left, right); var sharedResponseCodes = responseMapKeyDiff.SharedKey; var responses = new Dictionary <string, ChangedResponseBO>(); foreach (var responseCode in sharedResponseCodes) { var diff = _openApiDiff .ResponseDiff .Diff(left[responseCode], right[responseCode], context); if (diff != null) { responses.Add(responseCode, diff); } } var changedApiResponse = new ChangedAPIResponseBO(left, right, context) { Increased = responseMapKeyDiff.Increased, Missing = responseMapKeyDiff.Missing, Changed = responses, Extensions = _openApiDiff .ExtensionsDiff .Diff(left.Extensions, right.Extensions, context) }; return(ChangedUtils.IsChanged(changedApiResponse)); }
private Dictionary <string, OpenApiSchema> FilterProperties(TypeEnum type, Dictionary <string, OpenApiSchema> properties, DiffContextBO context) { var result = new Dictionary <string, OpenApiSchema>(); foreach (var(key, value) in properties) { if (IsPropertyApplicable(value, context) && OpenApiDiff .ExtensionsDiff.IsParentApplicable(type, value, value?.Extensions ?? new Dictionary <string, IOpenApiExtension>(), context)) { result.Add(key, value); } else { // Child property is not applicable, so required cannot be applied ChangedSchema.Required.Increased.Remove(key); } } return(result); }
protected abstract TD ComputeDiff(TC left, TC right, DiffContextBO context);
public ChangedOperationBO Diff( OpenApiOperation oldOperation, OpenApiOperation newOperation, DiffContextBO context) { var changedOperation = new ChangedOperationBO(context.URL, context.Method, oldOperation, newOperation) { Summary = _openApiDiff .MetadataDiff .Diff(oldOperation.Summary, newOperation.Summary, context), Description = _openApiDiff .MetadataDiff .Diff(oldOperation.Description, newOperation.Description, context), IsDeprecated = !oldOperation.Deprecated && newOperation.Deprecated }; if (oldOperation.RequestBody != null || newOperation.RequestBody != null) { changedOperation.RequestBody = _openApiDiff .RequestBodyDiff .Diff( oldOperation.RequestBody, newOperation.RequestBody, context.CopyAsRequest()); } var parametersDiff = _openApiDiff .ParametersDiff .Diff(oldOperation.Parameters.ToList(), newOperation.Parameters.ToList(), context); if (parametersDiff != null) { RemovePathParameters(context.Parameters, parametersDiff); changedOperation.Parameters = parametersDiff; } if (oldOperation.Responses != null || newOperation.Responses != null) { var diff = _openApiDiff .APIResponseDiff .Diff(oldOperation.Responses, newOperation.Responses, context.CopyAsResponse()); if (diff != null) { changedOperation.APIResponses = diff; } } if (oldOperation.Security != null || newOperation.Security != null) { var diff = _openApiDiff .SecurityRequirementsDiff .Diff(oldOperation.Security, newOperation.Security, context); if (diff != null) { changedOperation.SecurityRequirements = diff; } } changedOperation.Extensions = _openApiDiff .ExtensionsDiff .Diff(oldOperation.Extensions, newOperation.Extensions, context); return(ChangedUtils.IsChanged(changedOperation)); }
public CacheKey(string left, string right, DiffContextBO context) { this.left = left; this.right = right; this.context = context; }
public virtual ChangedSchemaBO Diff <T>( OpenApiComponents leftComponents, OpenApiComponents rightComponents, T left, T right, DiffContextBO context) where T : OpenApiSchema { var leftEnumStrings = left.Enum.Select(x => ((IOpenApiPrimitive)x)?.GetValueString()).ToList(); var rightEnumStrings = right.Enum.Select(x => ((IOpenApiPrimitive)x)?.GetValueString()).ToList(); var leftDefault = (IOpenApiPrimitive)left.Default; var rightDefault = (IOpenApiPrimitive)right.Default; var changedEnum = ListDiff.Diff(new ChangedEnumBO(leftEnumStrings, rightEnumStrings, context)); ChangedSchema.Context = context; ChangedSchema.OldSchema = left; ChangedSchema.NewSchema = right; ChangedSchema.IsChangeDeprecated = !left.Deprecated && right.Deprecated; ChangedSchema.IsChangeTitle = left.Title != right.Title; ChangedSchema.Required = ListDiff.Diff(new ChangedRequiredBO(left.Required.ToList(), right.Required.ToList(), context)); ChangedSchema.IsChangeDefault = leftDefault?.GetValueString() != rightDefault?.GetValueString(); ChangedSchema.Enumeration = changedEnum; ChangedSchema.IsChangeFormat = left.Format != right.Format; ChangedSchema.ReadOnly = new ChangedReadOnlyBO(left.ReadOnly, right.ReadOnly, context); ChangedSchema.WriteOnly = new ChangedWriteOnlyBO(left.WriteOnly, right.WriteOnly, context); ChangedSchema.MinLength = new ChangedMinLengthBO(left.MinLength, right.MinLength, context); ChangedSchema.MaxLength = new ChangedMaxLengthBO(left.MaxLength, right.MaxLength, context); var extendedDiff = OpenApiDiff.ExtensionsDiff.Diff(left.Extensions, right.Extensions, context); if (extendedDiff != null) { ChangedSchema.Extensions = extendedDiff; } var metaDataDiff = OpenApiDiff.MetadataDiff.Diff(left.Description, right.Description, context); if (metaDataDiff != null) { ChangedSchema.Description = metaDataDiff; } var leftProperties = left.Properties; var rightProperties = right.Properties; var propertyDiff = MapKeyDiff <string, OpenApiSchema> .Diff(leftProperties, rightProperties); foreach (var s in propertyDiff.SharedKey) { var diff = OpenApiDiff .SchemaDiff .Diff(leftProperties[s], rightProperties[s], Required(context, s, right.Required)); if (diff != null) { ChangedSchema.ChangedProperties.Add(s, diff); } } CompareAdditionalProperties(left, right, context); var allIncreasedProperties = FilterProperties(TypeEnum.Added, propertyDiff.Increased, context); foreach (var(key, value) in allIncreasedProperties) { ChangedSchema.IncreasedProperties.Add(key, value); } var allMissingProperties = FilterProperties(TypeEnum.Removed, propertyDiff.Missing, context); foreach (var(key, value) in allMissingProperties) { ChangedSchema.MissingProperties.Add(key, value); } return(IsApplicable(context)); }
protected override ChangedSchemaBO ComputeDiff(OpenApiSchema left, OpenApiSchema right, DiffContextBO context) { var leftRef = GetSchemaRef(left); var rightRef = GetSchemaRef(right); left = RefPointer.ResolveRef(_leftComponents, left, GetSchemaRef(left)); right = RefPointer.ResolveRef(_rightComponents, right, GetSchemaRef(right)); // If type of schemas are different, just set old & new schema, set changedType to true in // SchemaDiffResult and // return the object if (left == null || right == null || left.Type != right.Type || left.Format != right.Format) { return(GetTypeChangedSchema(left, right, context)); } // If schema type is same then get specific SchemaDiffResult and compare the properties var result = GetSchemaDiffResult(right, _openApiDiff); return(result.Diff(_leftComponents, _rightComponents, left, right, context)); }
private static bool IsPropertyApplicable(OpenApiSchema schema, DiffContextBO context) { return(!(context.IsResponse && schema.WriteOnly) && !(context.IsRequest && schema.ReadOnly)); }