diff --git a/.vscode/settings.json b/.vscode/settings.json
index 186b10bea..619467ff3 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -6,6 +6,7 @@
},
"cSpell.words": [
"csdl",
- "Hidi"
+ "Hidi",
+ "Xunit"
]
}
\ No newline at end of file
diff --git a/src/Microsoft.OpenApi/Attributes/ExperimentalAttribute.cs b/src/Microsoft.OpenApi/Attributes/ExperimentalAttribute.cs
new file mode 100644
index 000000000..3d2739e63
--- /dev/null
+++ b/src/Microsoft.OpenApi/Attributes/ExperimentalAttribute.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+#if !NET8_0_OR_GREATER
+namespace System.Diagnostics.CodeAnalysis
+{
+ ///
+ /// Indicates that an API is experimental and may change in the future.
+ ///
+ [AttributeUsage(
+ AttributeTargets.Assembly |
+ AttributeTargets.Module |
+ AttributeTargets.Class |
+ AttributeTargets.Struct |
+ AttributeTargets.Enum |
+ AttributeTargets.Constructor |
+ AttributeTargets.Method |
+ AttributeTargets.Property |
+ AttributeTargets.Field |
+ AttributeTargets.Event |
+ AttributeTargets.Interface |
+ AttributeTargets.Delegate,
+ Inherited = false)]
+ internal sealed class ExperimentalAttribute : Attribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The diagnostic ID reported when the API is used.
+ public ExperimentalAttribute(string diagnosticId)
+ {
+ DiagnosticId = diagnosticId;
+ }
+
+ ///
+ /// Gets the diagnostic ID reported when the API is used.
+ ///
+ public string DiagnosticId { get; }
+
+ ///
+ /// Gets or sets the URL format used by the diagnostic.
+ ///
+ public string? UrlFormat { get; set; }
+ }
+}
+#endif
diff --git a/src/Microsoft.OpenApi/Interfaces/IDeepCopyable.cs b/src/Microsoft.OpenApi/Interfaces/IDeepCopyable.cs
new file mode 100644
index 000000000..17e75f90c
--- /dev/null
+++ b/src/Microsoft.OpenApi/Interfaces/IDeepCopyable.cs
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Microsoft.OpenApi;
+///
+/// Interface for deep copyable objects.
+///
+/// The type of the resulting object.
+[System.Diagnostics.CodeAnalysis.Experimental("OPENAPI001")]
+public interface IDeepCopyable
+{
+ ///
+ /// Create a deep copy of the current instance.
+ ///
+ [System.Diagnostics.CodeAnalysis.Experimental("OPENAPI001")]
+ T CreateDeepCopy();
+}
diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
index 81729fa20..7cb3f4d73 100644
--- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
+++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
@@ -9,7 +9,7 @@
true
true
- NU5048
+ $(NoWarn);NU5048;OPENAPI001
enable
README.md
diff --git a/src/Microsoft.OpenApi/Models/BaseOpenApiReference.cs b/src/Microsoft.OpenApi/Models/BaseOpenApiReference.cs
index d32080890..647cf77fd 100644
--- a/src/Microsoft.OpenApi/Models/BaseOpenApiReference.cs
+++ b/src/Microsoft.OpenApi/Models/BaseOpenApiReference.cs
@@ -295,6 +295,12 @@ internal void EnsureHostDocumentIsSet(OpenApiDocument currentDocument)
Utils.CheckArgumentNull(currentDocument);
hostDocument ??= currentDocument;
}
+
+ internal void SetHostDocument(OpenApiDocument currentDocument)
+ {
+ Utils.CheckArgumentNull(currentDocument);
+ hostDocument = currentDocument;
+ }
///
/// Gets the property value from a JsonObject node.
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
index 4832619f7..98c013fcc 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
@@ -9,7 +9,7 @@ namespace Microsoft.OpenApi
///
/// Callback Object: A map of possible out-of band callbacks related to the parent operation.
///
- public class OpenApiCallback : IOpenApiExtensible, IOpenApiCallback
+ public class OpenApiCallback : IOpenApiExtensible, IOpenApiCallback, IDeepCopyable
{
///
public Dictionary? PathItems { get; set; }
@@ -113,5 +113,11 @@ public IOpenApiCallback CreateShallowCopy()
{
return new OpenApiCallback(this);
}
+ ///
+ [System.Diagnostics.CodeAnalysis.Experimental("OPENAPI001")]
+ public IOpenApiCallback CreateDeepCopy()
+ {
+ return new OpenApiDeepCopyContext().Copy(this);
+ }
}
}
diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
index c2f420ada..ac96909da 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
@@ -10,7 +10,7 @@ namespace Microsoft.OpenApi
///
/// Components Object.
///
- public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible
+ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible, IDeepCopyable
{
///
/// An object to hold reusable Objects.
@@ -96,6 +96,13 @@ public OpenApiComponents(OpenApiComponents? components)
Extensions = components?.Extensions != null ? new Dictionary(components.Extensions) : null;
}
+ ///
+ [System.Diagnostics.CodeAnalysis.Experimental("OPENAPI001")]
+ public OpenApiComponents CreateDeepCopy()
+ {
+ return new OpenApiDeepCopyContext().Copy(this);
+ }
+
///
/// Serialize to Open API v3.2.
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiContact.cs b/src/Microsoft.OpenApi/Models/OpenApiContact.cs
index 385129af7..d61be3fb8 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiContact.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiContact.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
@@ -9,7 +9,7 @@ namespace Microsoft.OpenApi
///
/// Contact Object.
///
- public class OpenApiContact : IOpenApiSerializable, IOpenApiExtensible
+ public class OpenApiContact : IOpenApiSerializable, IOpenApiExtensible, IDeepCopyable
{
///
/// The identifying name of the contact person/organization.
@@ -47,6 +47,12 @@ public OpenApiContact(OpenApiContact contact)
Email = contact?.Email ?? Email;
Extensions = contact?.Extensions != null ? new Dictionary(contact.Extensions) : null;
}
+ ///
+ [System.Diagnostics.CodeAnalysis.Experimental("OPENAPI001")]
+ public OpenApiContact CreateDeepCopy()
+ {
+ return new OpenApiDeepCopyContext().Copy(this);
+ }
///
/// Serialize to Open Api v3.2
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiDeepCopyContext.cs b/src/Microsoft.OpenApi/Models/OpenApiDeepCopyContext.cs
new file mode 100644
index 000000000..a2fe48f87
--- /dev/null
+++ b/src/Microsoft.OpenApi/Models/OpenApiDeepCopyContext.cs
@@ -0,0 +1,922 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+#pragma warning disable CS0618
+
+using System;
+using System.Collections.Generic;
+#if NET
+using System.Collections.Immutable;
+#endif
+using System.Linq;
+using System.Net.Http;
+using System.Runtime.CompilerServices;
+using System.Text.Json.Nodes;
+
+namespace Microsoft.OpenApi;
+
+internal sealed class OpenApiDeepCopyContext
+{
+ private readonly Dictionary